diff options
Diffstat (limited to 'util')
40 files changed, 0 insertions, 23552 deletions
diff --git a/util/ChangeLog b/util/ChangeLog deleted file mode 100644 index 426d4d3c9..000000000 --- a/util/ChangeLog +++ /dev/null @@ -1,1695 +0,0 @@ -2006-07-31 Werner Koch <[email protected]> - - * iobuf.c (iobuf_ioctl, fd_cache_invalidate): Allow closing all - open files. - -2006-07-29 Marcus Brinkmann <[email protected]> - - * secmem.c (init_pool): Close FD after establishing the mapping. - -2006-07-20 David Shaw <[email protected]> - - * http.c (send_request): A zero-length proxy is the same as no - proxy at all. Suggested by J. Scott Berg. - -2006-04-17 David Shaw <[email protected]> - - * miscutil.c (make_printable_string): Fix bug where some control - characters lose part of their ASCII representation. - -2006-04-11 David Shaw <[email protected]> - - * memory.c (realloc): Revert m_guard fix and stick an #error in - there to inform people not to use it. - -2006-04-11 Werner Koch <[email protected]> - - * iobuf.c (IOBUF_BUFFER_SIZE): New to replace hardwired 8192. - -2006-04-06 David Shaw <[email protected]> - - * memory.c (realloc): Fix compile problem with --enable-m-guard. - -2006-03-30 David Shaw <[email protected]> - - * cert.c (main): Fix test program build warning on OSX. - -2006-03-16 David Shaw <[email protected]> - - * cert.c (get_cert): Handle the fixed IPGP type with fingerprint. - -2006-03-08 David Shaw <[email protected]> - - * argparse.c (default_strusage): Update copyright year to 2006. - -2006-02-19 David Shaw <[email protected]> - - * http.c (send_request): A zero length proxy is the same as no - proxy. - -2006-02-14 Werner Koch <[email protected]> - - * errors.c (g10_errstr): Add NO_DATA. - -2006-01-26 David Shaw <[email protected]> - - * cert.c (get_cert): Disable IPGP types for now until the format - questions in the draft are settled. - - * srv.c (getsrv): Error on oversize SRV responses. - -2005-12-24 David Shaw <[email protected]> - - * cert.c (get_cert): Properly chase down CNAMEs pointing to CERTs. - -2005-12-23 David Shaw <[email protected]> - - * cert.c, Makefile.am: New code to do DNS CERT queries. - -2005-12-22 David Shaw <[email protected]> - - * srv.c, Makefile.am: Only build srv.c if we need to. - -2005-12-10 Ryan Lortie <[email protected]> (dshaw) - - * ttyio.c (tty_enable_completion, tty_disable_completion): Add - checks for no_terminal so we don't try to open("/dev/tty") when - invoked with --no-tty. - -2005-12-06 David Shaw <[email protected]> - - * Makefile.am: Some cleanup so we don't build files that are - completely ifdeffed out. This causes a warning on Sun's cc. Do - the internal regex code as well for consistency. - - * mkdtemp.c (mkdtemp): Fix warning. - - * secmem.c, assuan-buffer.c, dotlock.c: Fix a few warnings from - printf-ing %p where the arg wasn't void *. - -2005-11-02 David Shaw <[email protected]> - - * util.c [!HAVE_DECL_GETPAGESIZE]: Prototype getpagesize() if - unistd.h doesn't have it (for MinGW). - -2005-09-22 Werner Koch <[email protected]> - - * iobuf.c (iobuf_get_filelength): New arg OVERFLOW. - (iobuf_get_filelength) [W32]: Use GetFileSizeEx if available. - * fileutil.c (is_file_compressed): Take care of the OVERFLOW - -2005-08-31 David Shaw <[email protected]> - - * fileutil.c (untilde): New. Expand ~/foo and ~username/foo - filenames into full paths using $HOME if possible, or - getpwuid/getpwnam if necessary. - (make_filename): Use it here. - -2005-07-28 Werner Koch <[email protected]> - - * pka.c: New. - (parse_txt_record): Changed from v=1 to v=pka1. - - * Makefile.am (pka-test): new. - -2005-07-27 Werner Koch <[email protected]> - - * memory.c (FNAMEX, FNAMEXM): New macros to cope with the now used - names xmalloc style names. - -2005-07-18 Werner Koch <[email protected]> - - * ttyio.c (do_get): Move printing of the prompt after disabling - echo. Suggested by Scott Worley. - -2005-06-23 David Shaw <[email protected]> - - * http.c (make_radix64_string): Add '=' padding as per standard. - (send_request, http_open, http_open_document): Clean up auth code. - Can now support different auth for a proxy and the file being - requested via that proxy. Unescape auth strings. - -2005-06-22 David Shaw <[email protected]> - - * memrchr.c (memrchr): Not all compilers allow initializing based - on a variable that is also being initialized. Noted by Nelson - H. F. Beebe. - -2005-06-21 David Shaw <[email protected]> - - * http.c (send_request, http_open, http_open_document): Pass in - auth and proxyauth that can override the in-url auth. - - * http.c (send_request): Need == after the radix64-encoded basic - auth string. - -2005-06-08 David Shaw <[email protected]> - - * dotlock.c [HAVE_DOSISH_SYSTEM]: Fix unused function warnings on - mingw32. Noted by Joe Vender. - -2005-05-31 Werner Koch <[email protected]> - - * regcomp.c (MB_CUR_MAX) [_WIN32]: Define it only if not defined. - -2005-05-29 David Shaw <[email protected]> - - * strgutil.c (set_native_charset) [_WIN32]: Add alias for codepage - CP65001 to utf-8. - -2005-05-19 Werner Koch <[email protected]> - - * membuf.c: New. Taken from gnupg 1.9. - -2005-05-05 David Shaw <[email protected]> - - * miscutil.c (add_days_to_timestamp): Remove as unused. - -2005-04-12 David Shaw <[email protected]> - - * assuan-client.c: Fix warning on OSX. - - * memrchr.c: New replacement function. - - * assuan-buffer.c: Use it here. - -2005-04-04 Werner Koch <[email protected]> - - * memory.c (xcalloc, xcalloc_secure): New wrappers. - - * assuan-client.c (assuan_transact): Factored all code out to .. - (assuan_transact2): .. new. Add arg OKAY_CB. Wipe the memory - processed though that callback. - -2005-03-31 Werner Koch <[email protected]> - - * isascii.c: New. This is an autoconf replacement function. - - * Makefile.am (assuan_source): New. Only used when agent support - has been requested. - * assuan-buffer.c, assuan-client.c, assuan-defs.h, - * assuan-errors.c, assuan-logging.c, assuan-socket-connect.c, - * assuan-socket.c, assuan-util.c, assuan-connect.c: New. Taken - from libassuan 0.6.9 and adjusted for our limited use of Assuan. - -2005-03-18 David Shaw <[email protected]> - - * ttyio.c (tty_enable_completion, tty_disable_completion): Enable - and disable readline completion. - (init_ttyfp): Completion is disabled by default. - -2005-03-14 Werner Koch <[email protected]> - - * miscutil.c (isotimestamp): New. - -2005-03-10 Werner Koch <[email protected]> - - * secmem.c (secmem_realloc): Take control information into account - when checking whether a resize is needed. - -2005-03-08 Werner Koch <[email protected]> - - * miscutil.c (asctimestamp) [W32]: Don't use %Z. - -2005-02-03 Werner Koch <[email protected]> - - * w32reg.c (read_w32_registry_string): Fallback to HKLM also for a - missing name. - - * http.c (connect_server): Define ERR outside of the !W32 block. - -2005-02-01 David Shaw <[email protected]> - - * http.c (connect_server): Fix fd leak when connecting to a - round-robin server set that has some down servers. Noted by Phil - Pennock. - -2005-01-20 Werner Koch <[email protected]> - - * simple-gettext.c (set_gettext_file): Use MO files depending on - the installation directory. Add new arg REGKEY. - -2005-01-18 Werner Koch <[email protected]> - - * argparse.c (default_strusage): Changed default copyright year to - 2005. - - * strgutil.c (handle_iconv_error): Print error messages only once. - (native_to_utf8, utf8_to_native): Ditto. - -2005-01-11 Werner Koch <[email protected]> - - * strgutil.c (set_native_charset) [W32]: Use the alias table from - libiconv 1.9.2. - -2005-01-13 David Shaw <[email protected]> - - * http.c (connect_server): Use INADDR_NONE instead of - SOCKET_ERROR. Noted by Timo. - -2005-01-06 Werner Koch <[email protected]> - - * strgutil.c (set_native_charset): Assume that ASCII, - ANSI_X3.4-1968 and 646 are actually meant as Latin-1. If - nl_langinfo is not available get the charset from environment - variables. For W32 use GetACP as error fallback. Removed Latin-15 - to Latin-1 aliasing. - -2004-12-28 David Shaw <[email protected]> - - * srv.h: Better implementation for the SRV check. We don't need - to actually check all the header files individually since the SRV - test compile uses them together. - -2004-12-20 Werner Koch <[email protected]> - - * strgutil.c (handle_iconv_error): Turn diagnostics into warnings - so that gpg does not return with failure. - (native_to_utf8, utf8_to_native): Ditto. - -2004-12-16 Werner Koch <[email protected]> - - * iobuf.c (fd_cache_strcmp) [W32]: Casting is a Bad Thing. Cast to - an unsigned char pointer and to an unsigned integer. - -2004-12-18 David Shaw <[email protected]> - - * ttyio.c: Use only HAVE_LIBREADLINE to detect readline - availability. - -2004-12-16 David Shaw <[email protected]> - - * srv.h: Don't include arpa/nameser.h unless we have it. Include - "types.h" for u16. - - * secmem.c (secmem_init): Return a flag to indicate whether we got - the lock. - -2004-12-06 Werner Koch <[email protected]> - - * iobuf.c (fd_cache_strcmp): New. Use whenever we compare - filenames for the fd_cache. This is needed because the backslash - is an alias for a slash under W32. Reported by Tobias Winkler. - -2004-12-03 David Shaw <[email protected]> - - * http.c (send_request): Include the port if non-80 in the Host: - header. Noted by Jason Harris. - -2004-11-03 Timo Schulz <[email protected]> - - * strgutil.c (w32_strerror): New. - * ttyio.c (init_ttyfp, tty_printf, do_get): Use it here. - * iobuf.c (fd_cache_open, file_filter): Likewise. - (iobuf_seek, translate_file_handle): Likewise. - -2004-11-02 Werner Koch <[email protected]> - - * strgutil.c (load_libiconv): Use log_info to avoid failures when - iconv.dll is not installed. - -2004-10-31 Werner Koch <[email protected]> - - * simple-gettext.c (get_string): Removed debugging hack. - -2004-10-27 Werner Koch <[email protected]> - - * simple-gettext.c: Removed windows.h. - (get_string): On the fly translation from utf-8 to active - character set. - - * strgutil.c (load_libiconv) [_WIN32]: new. - (set_native_charset) [_WIN32]: Call it here and autodetect the - used code page. - (native_to_utf8, utf8_to_native): Reverted arguments for - iconv_open. - (handle_iconv_error): Made this function match iconv_open argumnet - ordering. - (utf8_to_native): Disable all quoting for DELIM == -1. - -2004-10-26 Werner Koch <[email protected]> - - * strgutil.c (mem2str): Translated comment to English. - (handle_iconv_error) [USE_GNUPG_ICONV]: New. - (set_native_charset) [USE_GNUPG_ICONV]: Added iconv based - conversion checks. - (native_to_utf8, utf8_to_native): Added iconv based conversion. - -2004-10-21 Werner Koch <[email protected]> - - * vasprintf.c: Removed. It was used only at one place and I don't - want to get into build problems in 1.4. - -2004-10-18 David Shaw <[email protected]> - - * http.c (connect_server, send_request): Use the URI scheme as the - SRV tag rather than hard-coding _hkp. - -2004-10-16 David Shaw <[email protected]> - - * http.c (connect_server): [_WIN32] actually fill in the sin_addr - so we aren't always talking to localhost. Add some general sanity - checking of parameters learned from gethostbyname(). - -2004-10-15 Werner Koch <[email protected]> - - * vasprintf.c: New. Taken from gnupg 1.9. - -2004-10-14 Werner Koch <[email protected]> - - * iobuf.c (iobuf_get_fd): Removed double check on directfp and - cats it to FILEP becuase directfp is actually a void *. Notes by - Stefan. - -2004-10-13 Werner Koch <[email protected]> - - * logger.c (g10_log_error_f, g10_log_fatal_f, g10_log_info_f) - (g10_log_debug_f, print_prefix_f): Removed. - - * iobuf.c (iobuf_is_pipe_filename): New. - (iobuf_get_fd): New. - - * fileutil.c (is_file_compressed): Use it here. - -2004-09-30 David Shaw <[email protected]> - - * iobuf.c (pop_filter): Make static. - - * dotlock.c (destroy_dotlock): New. Remove the handle from the - list of locks. - (release_dotlock): Don't act if we don't have any locks at all. - From Werner on stable branch. - -2004-09-10 David Shaw <[email protected]> - - * http.c (make_radix64_string, do_parse_uri, send_request): Add - basic auth for proxies and direct requests. Suggested by Florent - Thoumie. - - * http.c (main): Fix test code for http-test. - -2004-09-09 Werner Koch <[email protected]> - - * errors.c (g10_errstr): New error codes G10ERR_NO_CARD, - G10ERR_CANCELED. - - * ttyio.c (tty_get): Add readline support. - - * iobuf.c (iobuf_skip_rest): New. Orginal patch by Florian - Weimer. Added new argument PARTIAL. - -2004-08-19 David Shaw <[email protected]> - - * http.c (insert_escapes): Fix encoding problem for non-URI-safe - characters. Noted by Vladimir Novak. - -2004-05-21 David Shaw <[email protected]> - - * timegm.c: New replacement function. Removes the need for - setenv.c and unsetenv.c. - - * setenv.c: Removed. - - * unsetenv.c: Removed. - -2004-03-04 David Shaw <[email protected]> - - * iobuf.c (block_filter): Remove the old gpg indeterminate length - mode. - (iobuf_set_block_mode, iobuf_in_block_mode): Removed as - superfluous. - -2004-03-01 David Shaw <[email protected]> - - * iobuf.c (block_filter): Properly handle a partial body stream - that ends with a 5-byte length that happens to be zero. - -2004-02-28 David Shaw <[email protected]> - - * unsetenv.c: Fixed debugging typo. - -2004-02-24 Werner Koch <[email protected]> - - * secmem.c (lock_pool) [_AIX]: Also set errno. - -2004-02-21 David Shaw <[email protected]> - - * miscutil.c (hextobyte): Moved here from g10/misc.c so I can use - it in the keyserver helpers. - -2004-02-20 David Shaw <[email protected]> - - * mkdtemp.c: New (moved from g10/), setenv.c: New, unsetenv.c: - New. - - * Makefile.am: Include @LIBOBJS@ for replacement functions. - -2004-01-15 David Shaw <[email protected]> - - * argparse.c (default_strusage): Update copyright date. - (initialize): Avoid a number of -Wformat-nonliteral warnings. - These aren't actual problems, but the warnings bothered me. - - * miscutil.c (print_string2): New variation on print_string that - allows two delimiters. - (print_string): Call print_string2 to do work. - -2003-12-29 David Shaw <[email protected]> - - * g10u.c: Dead code. Remove. - - * Makefile.am: Don't compile g10u.c. - - * iobuf.c (block_filter): Properly handle a partial body stream - that ends with a 5-byte length. - -2003-12-28 David Shaw <[email protected]> - - * http.c (send_request, http_open_document, http_open): Pass the - http proxy from outside rather than pulling it from the - evironment. - -2003-12-28 Stefan Bellon <[email protected]> - - * riscos.c [__riscos__]: Better filetype handling (use a - different SWI) and removal of unnecessary function. - - * memory.c (out_of_core) [__riscos__]: Produce stack backtrace on - RISC OS if out_of_core() is called and M_GUARD is compiled in. - -2003-12-06 David Shaw <[email protected]> - - * http.c (send_request): Add a Host: header for virtual hosts. - -2003-12-04 David Shaw <[email protected]> - - * miscutil.c (answer_is_yes_no_default, answer_is_yes_no_quit): - Don't use alternate strings when not needed so we don't have to - re-translate them. Hopefully the comment will be enough to - indicate multiple match strings. - -2003-11-20 David Shaw <[email protected]> - - * miscutil.c (match_multistr): New. Match against each segment in - a string with tokens separated by |. - (answer_is_yes_no_default, answer_is_yes_no_quit, - answer_is_okay_cancel): Use it here to enable alternate - translations. - -2003-11-01 David Shaw <[email protected]> - - * http.c (connect_server): Differentiate between generic "can't - connect" errors and the more specific "host not found". Suggested - by Samuel Tardieu. - -2003-10-29 Werner Koch <[email protected]> - - * miscutil.c (answer_is_okay_cancel): New. - -2003-10-25 Werner Koch <[email protected]> - - * Makefile.am: Replaced INTLLIBS by LIBINTL. - -2003-10-23 Werner Koch <[email protected]> - - * secmem.c (lock_pool) [_AIX]: Don't use plock. - -2003-10-12 David Shaw <[email protected]> - - * srv.c: OSX 10.2.8/Darwin 6.8 seems to have some #include - ordering issues? Move sys/types.h up higher to work around. - -2003-10-08 Werner Koch <[email protected]> - - * ttyio.c (tty_print_string, tty_print_utf8_string2) - (tty_print_utf8_string): Made string arg const. - -2003-09-28 Timo Schulz <[email protected]> - - * strgutil.c [WIN32] (asprintf): New. - -2003-09-28 Werner Koch <[email protected]> - - * ttyio.c (tty_fprintf): New. - -2003-09-21 Timo Schulz <[email protected]> - - * http.c [WIN32]: Define MB_CUR_MAX. - (connect_server): use unsigned long since W32 does not have in_addr_t. - -2003-08-28 David Shaw <[email protected]> - - * dotlock.c, http.c, iobuf.c, simple-gettext.c, srv.c, srv.h, - strgutil.c, ttyio.c, w32reg.c: s/__MINGW32__/_WIN32/ to help - building on native Windows compilers. Requested by Brian Gladman. - From Werner on stable branch. - - * http.c (connect_server): Oops - forgot to freeaddrinfo(). - -2003-08-24 David Shaw <[email protected]> - - * http.c (connect_server): Try and use getaddrinfo if it is - available. Try for IPv6 via getaddrinfo() or a IPv6-ized - gethostbyname(). Suggested by Jun-ichiro itojun Hagino. - -2003-07-10 David Shaw <[email protected]> (from Werner on stable branch) - - * iobuf.c (check_special_filename): Replaced is isdigit by digitp - to avoid passing negative values and potential locale problems. - Problem noted by Christian Biere. - * strgutil.c (strlwr,strcasecmp,strncasecmp): Make sure we don't - pass a negative value. - * miscutil.c (scan_isodatestr): Ditto. - -2003-05-30 David Shaw <[email protected]> - - * srv.h, srv.c: Include windows.h with MINGW32. - -2003-05-24 David Shaw <[email protected]> - - * argparse.c, dotlock.c, fileutil.c, iobuf.c, miscutil.c, - simple-gettext.c, errors.c, http.c, memory.c, secmem.c, ttyio.c: - Edit all preprocessor instructions to remove whitespace before the - '#'. This is not required by C89, but there are some compilers - out there that don't like it. - -2003-05-21 Werner Koch <[email protected]> - - * fileutil.c (is_file_compressed): Fixed checking for "-" filename. - -2003-04-13 David Shaw <[email protected]> - - * srv.c (main): Test against wwwkeys.pgp.net. - - * srv.h: Grr. The RH7.3 Linux man page defines the fourth arg of - dn_expand as unsigned char*, but it is really char* according to - resolv.h. - -2003-03-23 David Shaw <[email protected]> - - * argparse.c (default_strusage): Change copyright date. - -2003-03-14 David Shaw <[email protected]> - - * srv.h, srv.c (getsrv): Use unsigned char rather than char. - Noted by Stefan Bellon. - -2003-03-11 David Shaw <[email protected]> - - * http.c (connect_server): Use DNS SRV to get a server list. Fail - over to A records if necessary. - - * Makefile.am, srv.h, srv.c: New DNS SRV handling code. - -2003-02-22 David Shaw <[email protected]> - - * ttyio.c (tty_print_utf8_string, tty_print_utf8_string2): Use 0 - to indicate a string with no maximum size. This prevents early - truncation of strings that contain control chars which are - expanded into \xXX form. - -2002-12-26 David Shaw <[email protected]> - - * iobuf.c (iobuf_flush): Only print debug info if debugging is on. - -2002-11-13 David Shaw <[email protected]> - - * secmem.c (lock_pool) [__CYGWIN__]: Don't print secmem warning. - From Werner on stable branch. - -2002-11-09 Werner Koch <[email protected]> - - * ttyio.c (TERMDEVICE): Removed. - (tty_get_ttyname): New. - (init_ttyfp): Use it here instead of the TERMDEVICE macro. - -2002-11-06 David Shaw <[email protected]> - - * w32reg.c (read_w32_registry_string): Fixed expanding of the - environment buffer; didn't worked at all. Reported by Thijmen - Klok. From Werner on stable branch. - - * secmem.c (secmem_free, secmem_term): Use wipememory2() instead - of memset() to overwrite secure memory - - * iobuf.c (direct_open): Handle mode 'b' if O_BINARY is available. - From Werner on stable branch. - - * fileutil.c: Comment from stable branch. - -2002-10-31 Stefan Bellon <[email protected]> - - * riscos.c (riscos_load_module, riscos_check_regexp): New. - (riscos_set_filetype_by_mimetype, riscos_dump_fdlist) - (riscos_fdopenfile, riscos_close_fds, riscos_renamefile) - (riscos_gstrans, riscos_list_openfiles, riscos_not_implemented): - Renamed functions to contain riscos prefix. - * dotlock.c [__riscos__]: Renames due to changes in riscos.c. - * fileutil.c [__riscos__]: Likewise. - -2002-10-29 Stefan Bellon <[email protected]> - - * fileutil.c: Removed unnecessary left-over includes for RISC OS. - (make_filename): Tidied up RISC OS stuff. - (compare_filenames) [__riscos__]: Compare with ascii_strcasecmp(). - (make_basename) [__riscos__]: Branch to own RISC OS routine from - here. - - * riscos.c (riscos_make_basename): New. - -2002-10-28 Stefan Bellon <[email protected]> - - * fileutil.c (make_basename) [__riscos__]: Cut off RISC OS' filing - systems from filepath. - - * riscos.c (riscos_get_filetype_from_string, riscos_get_filetype): - Added. - (riscos_set_filetype_by_number): Made public. - -2002-10-19 David Shaw <[email protected]> - - * Makefile.am, regcomp.c, regex.c, regex_internal.c, - regex_internal.h, regexec.c: Add new regex files from glibc 2.3.1. - -2002-10-17 David Shaw <[email protected]> - - * http.c (connect_server): Try all A records for names with - multiple addresses until one answers for both MINGW32 and not - MINGW32. - -2002-10-10 David Shaw <[email protected]> - - * http.c (connect_server): Properly handle a single A record that - fails connect(). - -2002-10-03 David Shaw <[email protected]> - - * logger.c (g10_log_warning, log_set_strict): Add new log_warning - logger command which can be switched between log_info and - log_error via log_set_strict. - -2002-09-24 David Shaw <[email protected]> - - * http.c (connect_server): Try all A records for names with - multiple addresses until one answers (not MINGW32). - -2002-09-16 Werner Koch <[email protected]> - - * w32reg.c (read_w32_registry_string): Fallback to HLM. - -2002-09-12 Stefan Bellon <[email protected]> - - * fileutil.c (make_filename): Removed variable for RISC OS to - avoid compiler warning. - - * secmem.c: Removed static variable for RISC OS to avoid - compiler warning. - -2002-09-11 Werner Koch <[email protected]> - - * simple-gettext.c: Disable charset mappings. We do it now when - installing the files. - -2002-09-09 Werner Koch <[email protected]> - - * w32reg.c (read_w32_registry_string): Handle REG_EXPAND_SZ. - Suggested by Ryan Malayter. - - * strgutil.c (ascii_strcasecmp): Replaced by code from gnulib. - (ascii_strncasecmp): New. - -2002-09-02 Werner Koch <[email protected]> - - * simple-gettext.c (set_gettext_file): Make sure that we only use - backslashes. - - * strgutil.c (set_native_charset): Allow NULL as argument to use - nl_langinfo for selection. Mapped latin-15 to latin-1. - -2002-08-30 Werner Koch <[email protected]> - - * iobuf.c (block_filter): Removed the assert, so that one can pass - the first character of a message and use the block filter for - non partial length encoded packets. - -2002-08-06 Stefan Bellon <[email protected]> - - * ttyio.c [__riscos__]: Moved low-level RISC OS stuff to riscos.c. - * riscos.c: Use new SWI calling mechanism of UnixLib. - -2002-08-03 Stefan Bellon <[email protected]> - - * secmem.c (init_pool, secmem_term): Changed #if to #ifdef in - order to avoid warning with RISC OS' Norcroft C. - -2002-07-25 David Shaw <[email protected]> - - * secmem.c: "Warning" -> "WARNING" - -2002-07-05 Werner Koch <[email protected]> - - * argparse.c (initialize): We better exit after a read error so - that we don't run into an endless loop when reading a directory. - Noted by Andrew Suffield. - -2002-07-01 David Shaw <[email protected]> - - * argparse.c (optfile_parse): Fix variable typo - 'p2' should be - 'p' :) - -2002-06-29 Werner Koch <[email protected]> - - * argparse.c (optfile_parse): Renamed an auto I to P2 to avoid - shadowing warning. - -2002-06-21 Stefan Bellon <[email protected]> - - * riscos.c (riscos_global_defaults): New. - -2002-06-20 Stefan Bellon <[email protected]> - - * riscos.c (riscos_set_filetype_by_number, riscos_set_filetype): - New. Set RISC OS filetype according to MIME type. - -2002-06-14 David Shaw <[email protected]> - - * strgutil.c (pop_strlist): New function to pop the head off of a - strlist. - -2002-06-05 Timo Schulz <[email protected]> - - * fileutil.c (is_file_compressed): Corrected the magic values - for bzip2 and gzip. Noted by David. - -2002-05-22 Werner Koch <[email protected]> - - * fileutil.c (compare_filenames): Replaced stricmp by strcasecmp. - * miscutil.c (answer_is_yes_no_quit,answer_is_yes_no_default): Ditto. - - * strgutil.c (strncasecmp): New. - (memicmp): Removed. - -2002-05-10 Stefan Bellon <[email protected]> - - * memory.c (add_entry) [M_DEBUG]: Added some missing EXTRA_ALIGN. - (free_entry) [M_DEBUG]: Free secure memory via secmem_free. - (alloc_secure): Malloc at least 1 byte. - (realloc) [M_GUARD]: Added missing FNAMEARG to function call. - - * logger.c (g10_log_bug0) [__riscos__]: Make use of first - g10_log_bug0 function for later Norcroft compiler. - - * riscos.c: Added stdlib.h include. - -2002-05-04 Werner Koch <[email protected]> - - * http.c (write_server) [__MINGW32__]: Replaced WriteFile by send - because sockets don't work with WriteFile under NT anymore. - -2002-05-03 David Shaw <[email protected]> - - * argparse.c (optfile_parse): Remove quotes only if they totally - enclose the string, and do not occur within the string. This - makes specifying a program under Win32 easier when you need quotes - around part of a string, but not around the whole string. - -2002-05-02 Werner Koch <[email protected]> - - * memory.c (alloc): Malloc at least 1 byte. Noted by Winona Brown. - -2002-04-23 David Shaw <[email protected]> - - * miscutil.c: New function answer_is_yes_no_default() to give a - default answer. - -2002-04-22 Stefan Bellon <[email protected]> - - * riscos.c (riscos_open, riscos_fopen, riscos_fstat, set_filetype): - Removed as they're not needed anymore. - - * iobuf.c (direct_open) [__riscos__]: Don't allow opening of - directories. - -2002-04-08 Werner Koch <[email protected]> - - Fixed filename of last entry. - -2002-03-29 David Shaw <[email protected]> - - * miscutil.c (print_string, utf8_to_native): If a delimiter is - used, then quote the backslash character as well. Problem noted - by Rainer Perske. - -2002-03-15 Werner Koch <[email protected]> - - * argparse.c (optfile_parse): Fixed missing argument handling. - -2002-02-28 Timo Schulz <[email protected]> - - * http.c (write_server): Convert integer to a HANDLE for W32. - -2002-01-27 David Shaw <[email protected]> - - * iobuf.c (iobuf_fdopen, iobuf_sockopen): Do not cache fdopened - fds on close. - -2002-01-08 Werner Koch <[email protected]> - - * secmem.c (print_warn): Print a pointer to the FAQ. - -2002-01-05 Werner Koch <[email protected]> - - * argparse.c (default_strusage): Set default copyright date to 2002. - -2002-01-02 Stefan Bellon <[email protected]> - - * iobuf.c [__riscos__]: Updated include file name. - - * fileutil.c [__riscos__]: Ditto. - - * ttyio.d [__riscos__]: Ditto. - - * riscos.c [__riscos__]: Ditto. Added debugging code and - unified error messages. - -2001-12-27 David Shaw <[email protected]> - - * errors.c (g10_errstr): Added G10ERR_KEYSERVER - -2001-12-27 Werner Koch <[email protected]> - - * simple-gettext.c [MINGW32]: Fixed last changed. - -2001-12-22 Stefan Bellon <[email protected]> - - * memory.c (realloc): Fixed realloc not working when M_GUARD is - defined and first parameter is NULL. - -2001-12-22 Timo Schulz <[email protected]> - - * fileutil.c (is_file_compressed): New. - -2001-12-19 Werner Koch <[email protected]> - - * simple-gettext.c, w32reg.c [CYGWIN32]: Allow to use this file - -2001-10-11 Werner Koch <[email protected]> - - * http.c (do_parse_uri): Changed initialization of the port number - so that it does also work with x-hkp. By David Shaw. - -2001-09-19 Werner Koch <[email protected]> - - * w32reg.c (get_root_key): New. - (read_w32_registry_string): Use it here. - (write_w32_registry_string): New. Contributed by Timo. - - * iobuf.c (iobuf_ioctl): New command to disable fd - caching. Implemented no_cache flag where needed. - (iobuf_sockopen): Always set no_cache flag. - - * strgutil.c (utf8_to_native): Add a delim arg and changed all - callers. Make sure that quoting is done when translation is - disabled. - * miscutil.c (print_utf8_string2): New. - -2001-09-17 Werner Koch <[email protected]> - - * miscutil.c (print_string): Use explicit ranges and not iscntrl(). - (make_printable_string): Ditto. - -2001-09-07 Werner Koch <[email protected]> - - * strgutil.c (strsep): New, taken from glibc 2.2.1. - -2001-09-03 Werner Koch <[email protected]> - - * miscutil.c (strtimestamp,asctimestamp): Avoid trigraphs. - -2001-08-21 Stefan Bellon <[email protected]> - - * riscos.c [__riscos__] (close_fds): Fixed possible endless loop. - -2001-08-20 Werner Koch <[email protected]> - - Applied patches from Stefan Bellon <[email protected]> to support - RISC OS. Nearly all of these patches are identified by the - __riscos__ macro. - * secmem.c [__riscos__]: Disabled secure memory stuff. - * dotlock.c, ttyio.c [__riscos__]: Adapted for RISC OS - * fileutil.c, iobuf.c: Adapted for RISC OS; mainly replaced - hardcoded path separators with EXTSEP_S like macros. - * http.c (send_request): Use macros for the env-var name. - * logger.c [__riscos__]: Do an fflush at the end of each log - function. - * memory.c [__riscos__]: Minor patches - * riscos.c (set_filetype): New. - - * secmem.c (lock_pool): Under HPUX mlock is broken but we might - have plock, so we use this to lock the entire process. By Albert - Chin. - -2001-07-03 Werner Koch <[email protected]> - - * strgutil.c (utf8_to_native): Fixed printing of invalid utf-8 - characters. Thomas Roessler reported that the escaping didn't work - correct. - -2001-06-12 Werner Koch <[email protected]> - - * strgutil.c (ascii_memistr,ascii_isupper,ascii_islower, - ascii_toupper,ascii_tolower, ascii_strcasecmp, ascii_memcasecmp): New. - (set_native_charset): Use ascii_strcasecmp() - * fileutil.c (compare_filenames): Ditto - * miscutil.c (answer_is_yes): Ditto. - (answer_is_yes_no_quit): Ditto. - -2001-06-06 Werner Koch <[email protected]> - - * strgutil.c (vasprintf) [__MINGW32__]: New. Taken from libiberty. - * ttyio.c (tty_printf) [__MINGW32__]: Replaced the sprintf with - the new vasprintf. - -2001-06-05 Werner Koch <[email protected]> - - * dotlock.c (make_dotlock): Typo fixes. - -2001-05-25 Werner Koch <[email protected]> - - * ttyio.c (do_get): Fixed a serious format string bug. Thanks to - fish stiqz. - -2001-05-23 Werner Koch <[email protected]> - - * secmem.c (EPERM): Try to work around a Slackware problem. - -2001-05-05 Werner Koch <[email protected]> - - * http.c (http_start_data): Flush before writing. - (http_wait_response): No need to flush here. - -2001-04-27 Werner Koch <[email protected]> - - * memory.c (out_of_core): Print an explanation on reasons why - secret memory can get exhausted. - -2001-04-23 Werner Koch <[email protected]> - - * http.c (http_wait_response): Implement new flag to inhibit the - TCP shutdown. - -2001-04-20 Werner Koch <[email protected]> - - * http.c (http_start_data): Use write_server and not the iobuf - stuff. I wonder why we are at all using write_server - shouldn't - it be handled by iobuf? - - * strgutil.c (set_native_charset): Allow utf-8 by introducing the - new no_translation variable. - (native_to_utf8): Handle no_translation. - (utf8_to_native): Ditto. - -2001-04-19 Werner Koch <[email protected]> - - * miscutil.c (asctimestamp): Handle negative times. We must do - this because Windoze segvs on negative times passed to gmtime(). - (strtimestamp): Ditto. - -2001-04-14 Werner Koch <[email protected]> - - * strgutil.c (utf8_to_native): Fixed a segv. Thanks to Keith Clayton. - -2001-04-13 Werner Koch <[email protected]> - - * iobuf.c (iobuf_fopen): Removed because it is not used and - furthermore mode is ignored for an fname of "-". Suggested by - Florian Weimer. - -2001-04-02 Werner Koch <[email protected]> - - * iobuf.c (translate_file_handle): New. Use this function - everywhere in this file. - (iobuf_translate_file_handle): Always use the osfhandle stuff here - because callers don't know the implementation details of iobuf and - they expect that the handles are translated. - -2001-03-29 Werner Koch <[email protected]> - - * miscutil.c (answer_is_yes): An empty string does now return no. - (answer_is_yes_no_quit): Likewise. - - * iobuf.c (iobuf_close): Burn the buffers. - -2001-03-26 Werner Koch <[email protected]> - - * ttyio.c: Define TERMDEVICE depending on OS. - - * http.c (http_start_data): send a CRLF and not just a LF. - Pointed out by Steven Murdoch. - -2001-03-13 Werner Koch <[email protected]> - - * iobuf.c (iobuf_sockopen): New. - (sock_filter) [__MINGW32__]: New. - (iobuf_ioctl): New. - (file_filter): Implemented keep_open mode. - * http.c (http_open, http_wait_response): Replaced iobuf_fdopen by - iobuf_sockopen and use an iobuf_ioctl to avoid the dup(). - (deinit_sockets, init_sockets) [__MINGW32__]: New. - (connect_server, write_server): Add code to work with W32 sockets. - -2001-03-12 Werner Koch <[email protected]> - - * strgutil.c (check_trailing_chars,check_trailing_ws): New. - -2001-03-08 Werner Koch <[email protected]> - - * argparse.c (default_strusage): Changed year of printed copyright - to 2001. - - * iobuf.c (fd_cache_invalidate, fd_cache_close, fd_cache_open): New. - (direct_open): Invalidate the fd_cache for read access. - (file_filter): Cache the close here. - (iobuf_open): Use new my_fopen_ro macro to try the cache first. - -2001-03-07 Werner Koch <[email protected]> - - * iobuf.c: Made the old stdio file handling cpp conditional - controlled by FILE_FILTER_USES_STDIO and added a new - open/read/close based one. We don't need the stdio buffering - becuase we are doing our own buffering anyway. And it is a - prerequesite to allow the use of ReadFile et al for W32 which in - turn is needed to make the http stuff work there. The new W32 - stuff has also been implemented. Minor changes to all open functions. - (direct_open): New. - (file_filter): Core of the new read/write handling. - (iobuf_get_filelength): Use W32 API function here. But it is - currently limited to 2GB files. - (iobuf_seek): Ditto. - -2001-03-01 Werner Koch <[email protected]> - - * errors.c (g10_errstr): New codes UNU_SECKEY and UNU_PUBKEY. - -2000-12-28 Werner Koch <[email protected]> - - * dotlock.c: Made all_lockfiles volatile. - (remove_lockfiles): Made public. - -2000-11-30 Werner Koch <[email protected]> - - * iobuf.c (iobuf_translate_file_handle): New. - (iobuf_open, iobuf_create): Use it for special filenames - -2000-11-11 Paul Eggert <[email protected]> - - * iobuf.c (iobuf_get_filelength): Now returns off_t, not u32. - Remove kludges to worry about large files; the callers check - for files that are too large, and they should already be doing - the right thing in an implementation-independent way. - (fopen, fstat): Remove macros. - - * iobuf.c (iobuf_set_limit, iobuf_tell, iobuf_seek): - Use off_t, not ulong, for file offsets. - (<limits.h>): Include if needed. - (LONG_MAX, LONG_MIN): Define a substitute if needed. - (fseeko): Define a substitute if needed. - - * iobuf.c (iobuf_seek): Do not use %lu to report file - -2000-11-09 Werner Koch <[email protected]> - - * iobuf.c (iobuf_enable_special_filenames): New. - (check_special_filename): New. - (iobuf_open): check for special filenames. - (iobuf_create): Ditto. - -2000-10-23 Werner Koch <[email protected]> - - * secmem.c (lock_pool): Don't print warning for Windows. - -2000-10-16 Werner Koch <[email protected]> - - * secmem.c (lock_pool): Fixed error checking for Linux. - By James Troup. - -Thu Sep 14 14:20:38 CEST 2000 Werner Koch <[email protected]> - - * miscutil.c (answer_is_yes_no_quit): Swapped order of yes/no test - so that no is returned for an empty input. By David Champion. - -Wed Sep 6 17:55:47 CEST 2000 Werner Koch <[email protected]> - - * iobuf.c: Use fopen64 insead of fopen when available. - (iobuf_get_filelength): Use fstat64 when available but return - 2^32-1 if the file is larger than this value. - -Wed Sep 6 14:59:09 CEST 2000 Werner Koch <[email protected]> - - * secmem.c (secmem_realloc): check for failed secmem_malloc. By - Matt Kraai. - - * strgutil.c (utf8_to_native): Fixed null ptr problem. By - Giampaolo Tomassoni. - -Thu Jul 27 10:02:38 CEST 2000 Werner Koch <[email protected]> - - * iobuf.c: Use setmode() at several places to set stdin and stdout - to binary mode for MSDOS based systems - - * iobuf.c (underflow): Initialize dummy_len to keep memory checker happy. - -Fri Jun 9 10:09:52 CEST 2000 Werner Koch <[email protected]> - - * ttyio.c: Simulate termios with termios. By Dave Dykstra. - -Thu Jun 8 20:22:00 CEST 2000 Werner Koch <[email protected]> - - * secmem.c (lock_pool,secmem_init): Additional check for dropped privs. - -Tue May 30 16:37:55 CEST 2000 Werner Koch <[email protected]> - - * iobuf.c (iobuf_cancel): Fix for MSDOS. - -Fri Apr 14 19:37:08 CEST 2000 Werner Koch <[email protected]> - - * dotlock.c (disable_dotlock): New. Implmented this in the module. - -2000-03-09 14:04:22 Werner Koch ([email protected]) - - * argparse.c (default_strusage): Changed year of default copyright. - -Tue Mar 7 18:45:31 CET 2000 Werner Koch <[email protected]> - - * secmem.c (lock_pool): No more warning for QNX. By Sam Roberts. - -2000-03-02 15:51:04 Werner Koch ([email protected]) - - * ttyio.c (tty_print_utf8_string): Oops. - -Thu Mar 2 15:37:46 CET 2000 Werner Koch <[email protected]> - - * ttyio.c (tty_print_utf8_string2): New to allow a max output size. - -Wed Feb 23 10:07:57 CET 2000 Werner Koch <[email protected]> - - * miscutil.c (asctimestamp): Fix for possible buffer overflow by - large system returned date format string. - -Fri Dec 31 14:08:15 CET 1999 Werner Koch <[email protected]> - - * logger.c (log_inc_errorcount): New. - -Sat Dec 4 12:30:28 CET 1999 Werner Koch <[email protected]> - - * iobuf.c (iobuf_cancel): Broadcast the new Cancel mesaage to all - filters. - -Mon Nov 22 11:14:53 CET 1999 Werner Koch <[email protected]> - - * strgutil.c (strcasecmp): New. - - * secmem.c (pool_is_mmapped): Made volatile. - -Sat Oct 9 20:34:41 CEST 1999 Werner Koch <[email protected]> - - * Makefile.am: Removed libtool. - -Fri Oct 8 20:32:01 CEST 1999 Werner Koch <[email protected]> - - * w32reg.c: New. - * simple-gettext.c: Use the Registry to locate the mo file. - - * http.c (send_request): Add support for proxys; suggested by - Walter Hofmann. - (http_open_document): Pass flags to http_open. - -Fri Sep 17 12:56:42 CEST 1999 Werner Koch <[email protected]> - - - * secmem.c (lock_pool): Check for ENOSYS return my mlock() on - old SCOs. - - * ttyio.c (do_get): Replaced #if __MINGW32__ by #ifdef becuase - gcc 2.95.1 assigns a floating point value (0.2) to this macro, - which in turn can't be used in an expression. - -Wed Sep 15 16:22:17 CEST 1999 Werner Koch <[email protected]> - - - * simple-gettext.c: New. - -Wed Sep 1 15:30:44 CEST 1999 Werner Koch <[email protected]> - - - * argparse.c (arg_parse): Add standard options to the dump-options - output. - -Tue Aug 31 17:20:44 CEST 1999 Werner Koch <[email protected]> - - - * strgutil (utf8_to_native): Implemented. - (check_utf8_string): Removed. - - * miscutil.c (make_printable_string): Fixed possible buffer overflow. - (print_utf8_string): New. - - * ttyio.c (tty_print_utf8_string): New. - -Mon Aug 30 20:38:33 CEST 1999 Werner Koch <[email protected]> - - - * secmem.c (pool_okay): declared volatile. - - * miscutil.c (answer_is_yes): Always check for plain "yes". - (answer_is_yes_no_quit): Likewise. - - * dotlock.c (create_dotlock): Fixed segv during cleanup. - -Mon Jul 12 14:55:34 CEST 1999 Werner Koch <[email protected]> - - - * argparse.c (initialize): Init ret_xxx. - (optfile_parse): Remove quotes from arguments. - -Wed Jul 7 13:08:40 CEST 1999 Werner Koch <[email protected]> - - - * memory.c (membug): Use if either M_DEBUG or M_GUARD is used. - - * miscutil.c (scan_isodatestr): New. - - * logger.c (g10_log_mpidump): Moved to ../mpi/mpicoder.c - (g10_log_print_prefix): Renamed from print_prefix and made global. - - * Makefile.am: Support for libtool. - -Thu Jul 1 12:47:31 CEST 1999 Werner Koch <[email protected]> - - - * miscutil.c (make_printable_string): New. - - * strgutil.c (add_to_strlist2,append_to_strlist2): New. - -Tue Jun 29 21:44:25 CEST 1999 Werner Koch <[email protected]> - - - * secmem.c (USE_CAPABILITIES): Capabilities support (Remi). - -Sat Jun 26 12:15:59 CEST 1999 Werner Koch <[email protected]> - - - * dotlock.c (create_dotlock): s/uts/utsbuf/ cause there an Amdahl - system with the name UTS (Dave Dykstra). - - * secmem.c (DEFAULT_POOLSIZE): Doubled the size. - -Fri Jun 18 00:18:02 CEST 1999 Michael Roth <[email protected]> - - * iobuf.c: file_filter() Detection of EOF on terminals - improved/fixed (see Bug #21). - -Mon Jun 14 21:18:54 CEST 1999 Michael Roth <[email protected]> - - * ttyio.c: tty_no_terminal() new. - -Sat Jun 5 15:30:33 CEST 1999 Werner Koch <[email protected]> - - * strgutil.c (set_native_charset): Support Latin-2 - -Tue Jun 1 16:01:46 CEST 1999 Werner Koch <[email protected]> - - * iobuf.c (iobuf_get_real_fname): Made global and now keep a - copy of the name in the iobuf struct. - -Mon May 31 19:41:10 CEST 1999 Werner Koch <[email protected]> - - * iobuf.c (file_filter,block_filter): Speed patches (R�mi). - -Thu May 27 09:40:55 CEST 1999 Werner Koch <[email protected]> - - * miscutil.c (answer_is_yes_no_quit): New. - -Sun May 23 14:20:22 CEST 1999 Werner Koch <[email protected]> - - * dotlock.c: Tweaked to make it compile under mingw32 - * http.c: Disabled for mingw32. - -Sat May 22 22:47:26 CEST 1999 Werner Koch <[email protected]> - - * logger.c (log_set_logfile): New. - -Thu May 20 14:04:08 CEST 1999 Werner Koch <[email protected]> - - * memory.c (membug): Nanu, there was a const instead of a static. - - * strgutil.c (trim_trailing_chars): New. - -Mon May 17 21:54:43 CEST 1999 Werner Koch <[email protected]> - - * logger.c (g10_log_hexdump): Made 2nd arg a const. - -Wed Apr 28 13:03:03 CEST 1999 Werner Koch <[email protected]> - - * miscutil.c (asctimestamp): Use nl_langinfo (Ga�l Qu�ri). - -Sun Apr 18 10:11:28 CEST 1999 Werner Koch <[email protected]> - - * argparse.c (store_alias): Disabled becuase it is not used. - - * ttyio.c (tty_batchmode): New - -Sat Mar 20 11:44:21 CET 1999 Werner Koch <[email protected]> - - * http.c: Swapped to includes. - -Tue Mar 2 16:44:57 CET 1999 Werner Koch <[email protected]> - - * strgutil.c (get_native_charset): New. - -Fri Feb 26 17:55:41 CET 1999 Werner Koch <[email protected]> - - * secmem.c (memblock_struct): Force align (R�mi Guyomarch) - -Wed Feb 24 11:07:27 CET 1999 Werner Koch <[email protected]> - - * iobuf.c (block_filter): Fixed the oscillating partial packet chunks. - -Fri Feb 19 15:49:15 CET 1999 Werner Koch <[email protected]> - - * iobuf.c (iobuf_push_filter2): New to allow transer of context - ownership to the iobuf. Released the context where needed. - -Tue Feb 16 14:10:02 CET 1999 Werner Koch <[email protected]> - - * strgutil.c (add_to_strglist): Clear the new flags field - (append_to_strglist): Ditto. - - * dotlock.c (read_lockfile): terminate pidstr (Michael). - -Wed Feb 10 17:15:39 CET 1999 Werner Koch <[email protected]> - - * dotlock.c (remove_lockfiles): Add cleanup function. - (make_dotlock): Add deadlock check. - - * secmem.c (secmem_malloc): Changed error message. - -Wed Jan 20 21:40:21 CET 1999 Werner Koch <[email protected]> - - * http.c (http_wait_response): Moved the shutdown behind the dup - -Wed Jan 20 18:59:49 CET 1999 Werner Koch <[email protected]> - - * http.c (send_request): Removed double LF - -Tue Jan 19 19:34:58 CET 1999 Werner Koch <[email protected]> - - * * iobuf.c (iobuf_push_filter): Allow filters for temp streams - - (iobuf_write_temp): Ditto. - (iobuf_flush_temp): New. - (iobuf_unget_and_close_temp): Removed. - - * http.c (close_http_document): Renamed to http_close(). - (open_http_document): Renamed to http_open_document(). - (http_open): New. - (http_start_data): New. - (http_wait_response): New. - - -Sun Jan 17 11:04:33 CET 1999 Werner Koch <[email protected]> - - * strgutil.c (trim_trailing_ws): New. - -Sat Jan 16 12:03:27 CET 1999 Werner Koch <[email protected]> - - * http.c (connect_server): Fixed stupid bug. - -Sat Jan 16 09:27:30 CET 1999 Werner Koch <[email protected]> - - * http.c: New - - -Wed Jan 13 14:10:15 CET 1999 Werner Koch <[email protected]> - - * iobuf.c (iobuf_fdopen): New. - -Sat Jan 9 16:02:23 CET 1999 Werner Koch <[email protected]> - - * secmem.c (lock_pool): add another check that setuid() worked. - (secmem_init): Ditto. - -Thu Jan 7 18:00:58 CET 1999 Werner Koch <[email protected]> - - * iobuf.c (iobuf_clear_eof): Removed. - (underflow): Changed the eof handling. - (iobuf_pop_filter): Made static and renamed to pop_filter. - - * iobuf.c (iobuf_read_line): New. - -Sun Jan 3 15:28:44 CET 1999 Werner Koch <[email protected]> - - * dotlock.c (make_dotlock): print another informal message. - - (make_dotlock): Removed the cpp checks. - - -Tue Dec 29 14:41:47 CET 1998 Werner Koch <[email protected]> - - * secmem.c: Moved unistd.h out of the #ifdef - - * dotlock.c (make_dotlock): Sun has no SYS_NMLN - - * iobuf.c (iobuf_unget_and_close_temp): Reset .start - -Sat Dec 12 18:40:32 CET 1998 Werner Koch <[email protected]> - - * argparse.c (arg_pars): fixed opts[i] with negative index. - -Fri Nov 27 21:37:41 CET 1998 Werner Koch <[email protected]> - - * dotlock.c: Implemented - -Wed Nov 25 11:30:07 1998 Werner Koch ([email protected]) - - * iobuf.c (iobuf_pop_filter): Fixed sigsegv after error. - -Thu Nov 19 07:09:55 1998 Werner Koch <[email protected]> - - * miscutil.c (strtimevalue): New. - -Tue Nov 10 10:01:53 1998 Werner Koch ([email protected]) - - * strgutil.c (set_native_charset): New. - (native_to_utf8): Now handles koi8-r. - -Tue Nov 3 16:17:56 1998 Werner Koch ([email protected]) - - * strgutil.c (native_to_utf8): New. - (utf8_to_native): New, but only as a stub. - - * argparse.c (optfile_parse): Trimmed spaces from args. - - -Wed Oct 28 08:01:49 1998 me,,, (wk@tobold) - - * argparse.c (find_long_option): New. - (arg_parse): option=value is now allowed. Add a new internal - option "--dump-options". - -Thu Oct 22 16:25:49 1998 Michael Roth ([email protected]) - - * fileutil.c (make_basename): New. - (make_dirname): New. - -Wed Oct 21 12:20:29 1998 Werner Koch ([email protected]) - - * util.c (iobuf_flush): autoincreasing of a temp. iobuf - (iobuf_temp_with_content): New. - -Tue Oct 13 12:40:13 1998 Werner Koch ([email protected]) - - * util.c (.nofast): set this variable - -Wed Oct 7 19:27:50 1998 Werner Koch ([email protected]) - - * memory.c (m_print_stats): New. - -Tue Oct 6 09:53:56 1998 Werner Koch ([email protected]) - - * strgutil.c (memicmp): Add HAVE_MEMICMP. - -Mon Sep 21 19:45:01 1998 Werner Koch (wk@(none)) - - * secmem.c: New flags to allow suspend/resume of warnings. - -Fri Sep 18 16:25:47 1998 Werner Koch (wk@(none)) - - * secmem.c (lock_pool): Kludge for broken mlock on HPUX 10.20 - -Tue Sep 15 17:52:21 1998 Werner Koch (wk@(none)) - - * miscutil.c (asctimestamp): New. - -Mon Sep 14 09:38:18 1998 Werner Koch (wk@(none)) - - * secmem.c (init_pool): Now mmaps /dev/zero if we do not have MAP_ANON. - -Wed Sep 9 13:52:28 1998 Werner Koch (wk@(none)) - - * ttyio.c (do_get): Ctrl-D is now a valid but special character - -Mon Sep 7 13:52:41 1998 Werner Koch (wk@(none)) - - * iobuf.c (get_real_fname): New and changed file_filter datastructures - and their initialization. - -Tue Aug 11 15:12:35 1998 Werner Koch (wk@(none)) - - * miscutil.c (answer_is_yes): i18ned - -Sat Aug 8 18:35:00 1998 Werner Koch (wk@(none)) - - * ttyio.c (cleanup): New. - -Mon Aug 3 17:06:00 1998 Werner Koch (wk@(none)) - - * secmem.c (MAP_ANON): Add a macro test - -Wed Jul 29 14:53:34 1998 Werner Koch (wk@(none)) - - * ttyio.c (tty_get_answer_is_yes): New. - -Tue Jul 21 10:35:48 1998 Werner Koch (wk@(none)) - - * argparse.c: New option flag to distinguish options and commands. - -Sat Jul 18 19:49:30 1998 Werner Koch (wk@(none)) - - * argparse.c (arg_parse): Added -? as alias for -h - -Thu Jul 9 14:47:20 1998 Werner Koch ([email protected]) - - * secmem.c (secmem_init): Drops setuid if called with 0. - -Tue Jul 7 11:49:25 1998 Werner Koch ([email protected]) - - * logger.c (log_set_filename): New. - -Mon Jul 6 09:03:49 1998 Werner Koch ([email protected]) - - * strgutil.c (append_to_strlist): New. - -Thu Jul 2 15:55:44 1998 Werner Koch ([email protected]) - - * iobuf.c (block_filter): Add writing of OP partial length headers. - -Fri Jun 26 10:38:35 1998 Werner Koch ([email protected]) - - * ttyio.c (do_get): all iso8859-1 characters are now allowed. - -Thu Jun 25 15:57:21 1998 Werner Koch ([email protected]) - - * secmem.c (lock_pool): Removed left over test code. - -Wed Jun 10 07:39:41 1998 Werner Koch,mobil,,, (wk@tobold) - - * fileutil.c (compare_filenames): New. - - * argparse.c (arg_parse): New flag bit 6 to ignore --version - -Thu May 14 16:45:13 1998 Werner Koch ([email protected]) - - * argparse.c (show_help): Add some formatting stuff - -Fri May 8 17:06:49 1998 Werner Koch ([email protected]) - - * errors.c (strerror): New if !HAVE_STRERROR - -Mon May 4 19:48:03 1998 Werner Koch ([email protected]) - - * iobuf.c (iobuf_read): Code is now faster. - * (iobuf_write): ditto. - -Mon Apr 27 11:01:32 1998 Werner Koch ([email protected]) - - * strgutil.c (memicmp): New. - -Thu Mar 19 11:29:03 1998 Werner Koch ([email protected]) - - * strgutil.c (memistr): Add const to return and first arg. - -Sat Mar 7 11:54:35 1998 Werner Koch ([email protected]) - - * miscutil.c (print_string): New arg delim; changed all callers. - -Thu Mar 5 12:19:30 1998 Werner Koch ([email protected]) - - * errors.c: New strings. - -Thu Mar 5 12:06:31 1998 Werner Koch ([email protected]) - - * iobuf.c (iobuf_open): A name of "-" now opens stdin. - * fileutil.c (print_fname_stdout, print_fname_stdin): New. - -Fri Feb 27 10:20:03 1998 Werner Koch ([email protected]) - - * memory.c (m_is_secure): Removed. - * secmem.c (m_is_secure): Moved to here. - - * secmem.c (secmem_realloc): New. - * memory.c (M_GUARD,EXTRA_ALIGN): New (all functions). - -Thu Feb 26 14:36:51 1998 Werner Koch ([email protected]) - - * secmem.c (lock_pool): No error if EAGAIN is returned instead - of EPERM. - -Fri Feb 20 17:43:05 1998 Werner Koch ([email protected]) - - * ttyio.c [MINGW32]: Add support for mingw32. - -Tue Feb 17 19:43:44 1998 Werner Koch ([email protected]) - - * memory.c (dump_table_at_exit): New. - -Mon Feb 16 10:07:28 1998 Werner Koch ([email protected]) - - * argparse.c (show_version, show_help, default_strusage): Changed - according to GNU standards. - -Mon Feb 16 08:58:25 1998 Werner Koch ([email protected]) - - * iobuf.c (iobuf_peek): New - -Fri Feb 13 19:34:59 1998 Werner Koch ([email protected]) - - * iobuf.c (iobuf_seek): Set counters to new offset. - -Fri Feb 13 17:13:04 1998 Werner Koch ([email protected]) - - * logger.c (log_set_name, log_get_name): New. - (print_prefix, pgm_name): New, changed all function to make use it. - (log_mpidump): Removed the "DBG" prefix. - (log_hexdump): Ditto. - - * logger.c (printstr): Removed. - -Fri Feb 13 15:14:13 1998 Werner Koch ([email protected]) - - * argparse.c (show_help): New '\v' kludge. - - - - Copyright 1998, 1999, 2000, 2001, 2002, 2003, 2004, - 2005 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/util/Makefile.am b/util/Makefile.am deleted file mode 100644 index 48457c29f..000000000 --- a/util/Makefile.am +++ /dev/null @@ -1,73 +0,0 @@ -# Copyright (C) 1998, 1999, 2000, 2001, 2005 Free Software Foundation, Inc. -# -# This file is part of GnuPG. -# -# GnuPG is free software; you can redistribute it and/or modify -# it under the terms of the GNU General Public License as published by -# the Free Software Foundation; either version 2 of the License, or -# (at your option) any later version. -# -# GnuPG is distributed in the hope that it will be useful, -# but WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -# GNU General Public License for more details. -# -# You should have received a copy of the GNU General Public License -# along with this program; if not, write to the Free Software -# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA - -## Process this file with automake to produce Makefile.in - -INCLUDES = -I.. -I$(top_srcdir)/include -I$(top_srcdir)/intl - -noinst_LIBRARIES = libutil.a - -libutil_a_SOURCES = logger.c fileutil.c miscutil.c strgutil.c \ - ttyio.c argparse.c memory.c secmem.c errors.c iobuf.c \ - dotlock.c http.c pka.c membuf.c cert.c - -if USE_SIMPLE_GETTEXT -libutil_a_SOURCES+=simple-gettext.c -endif - -if HAVE_W32_SYSTEM -libutil_a_SOURCES+=w32reg.c -endif - -if ENABLE_AGENT_SUPPORT -libutil_a_SOURCES+=assuan-buffer.c assuan-client.c assuan-defs.h \ - assuan-errors.c assuan-logging.c assuan-socket-connect.c \ - assuan-connect.c assuan-socket.c assuan-util.c -endif - -if USE_INTERNAL_REGEX -libutil_a_SOURCES+=regex.c -endif - -if USE_DNS_SRV -libutil_a_SOURCES+=srv.c srv.h -endif - -# The internal regex code #includes these. -EXTRA_libutil_a_SOURCES = regcomp.c regexec.c regex_internal.c \ - regex_internal.h - -# LIBOBJS is for the replacement functions -libutil_a_DEPENDENCIES = @LIBOBJS@ -libutil_a_LIBADD = @LIBOBJS@ - -http-test: http.c - cc -DHAVE_CONFIG_H -I. -I. -I.. $(INCLUDES) $(LDFLAGS) -g -Wall \ - -DTEST -o http-test http.c libutil.a @LIBINTL@ @DNSLIBS@ @CAPLIBS@ - -srv-test: srv.c - cc -DHAVE_CONFIG_H -I. -I. -I.. $(INCLUDES) $(LDFLAGS) -g -Wall \ - -DTEST -o srv-test srv.c libutil.a @LIBINTL@ @DNSLIBS@ @CAPLIBS@ - -pka-test: pka.c - cc -DHAVE_CONFIG_H -I. -I. -I.. $(INCLUDES) $(LDFLAGS) -g -Wall \ - -DTEST -o pka-test pka.c libutil.a @LIBINTL@ @DNSLIBS@ @CAPLIBS@ - -cert-test: cert.c - cc -DHAVE_CONFIG_H -I. -I. -I.. $(INCLUDES) $(LDFLAGS) -g -Wall \ - -DTEST -o cert-test cert.c libutil.a @LIBINTL@ @DNSLIBS@ @CAPLIBS@ diff --git a/util/argparse.c b/util/argparse.c deleted file mode 100644 index cdc56bf3a..000000000 --- a/util/argparse.c +++ /dev/null @@ -1,1004 +0,0 @@ -/* [argparse.c wk 17.06.97] Argument Parser for option handling - * Copyright (C) 1998, 1999, 2000, 2001, 2003, - * 2004 Free Software Foundation, Inc. - * - * This file is part of GnuPG. - * - * GnuPG is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * GnuPG is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA - * - * - * Note: This is an independent version of the one in WkLib - */ - -#include <config.h> -#include <stdio.h> -#include <stdlib.h> -#include <ctype.h> -#include <string.h> - -#include "util.h" -#include "i18n.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 and --help - * 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 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 initialized */ - if( *arg->argc < 0 ) - log_bug("Invalid argument for ArgParse\n"); - } - - - if( arg->err ) { /* last option was erroneous */ - - if( filename ) { - if( arg->r_opt == -6 ) - log_error("%s:%u: argument not expected\n", filename, *lineno ); - else if( arg->r_opt == -5 ) - log_error("%s:%u: read error\n", filename, *lineno ); - else if( arg->r_opt == -4 ) - log_error("%s:%u: keyword too long\n", filename, *lineno ); - else if( arg->r_opt == -3 ) - log_error("%s:%u: missing argument\n", filename, *lineno ); - else if( arg->r_opt == -7 ) - log_error("%s:%u: invalid command\n", filename, *lineno ); - else if( arg->r_opt == -10 ) - log_error("%s:%u: invalid alias definition\n",filename,*lineno); - else - log_error("%s:%u: invalid option\n", filename, *lineno ); - } - else { - if( arg->r_opt == -3 ) - log_error("Missing argument for option \"%.50s\"\n", - arg->internal.last? arg->internal.last:"[??]" ); - else if( arg->r_opt == -6 ) - log_error("Option \"%.50s\" does not expect an argument\n", - arg->internal.last? arg->internal.last:"[??]" ); - else if( arg->r_opt == -7 ) - log_error("Invalid command \"%.50s\"\n", - arg->internal.last? arg->internal.last:"[??]" ); - else if( arg->r_opt == -8 ) - log_error("Option \"%.50s\" is ambiguous\n", - arg->internal.last? arg->internal.last:"[??]" ); - else if( arg->r_opt == -9 ) - log_error("Command \"%.50s\" is ambiguous\n", - arg->internal.last? arg->internal.last:"[??]" ); - else - log_error("Invalid option \"%.50s\"\n", - arg->internal.last? arg->internal.last:"[??]" ); - } - if( arg->err != 1 || arg->r_opt == -5 ) - exit(2); - arg->err = 0; - } - - /* clearout 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 - */ -#if 0 - ALIAS_DEF a = 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 inverse=0; - int in_alias=0; - - if( !fp ) /* same as 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( inverse ) /* this does not have an effect, hmmm */ - arg->r_opt = -arg->r_opt; - if( !opts[idx].short_opt ) /* unknown command/option */ - arg->r_opt = (opts[idx].flags & 256)? -7:-2; - else if( !(opts[idx].flags & 7) ) /* does not take an arg */ - arg->r_type = 0; /* okay */ - else if( (opts[idx].flags & 8) ) /* argument is optional */ - arg->r_type = 0; /* okay */ - else /* required argument */ - arg->r_opt = -3; /* error */ - break; - } - else if( state == 3 ) { /* no argument found */ - if( in_alias ) - arg->r_opt = -3; /* error */ - else if( !(opts[idx].flags & 7) ) /* does not take an arg */ - arg->r_type = 0; /* okay */ - else if( (opts[idx].flags & 8) ) /* no optional argument */ - arg->r_type = 0; /* okay */ - else /* no required argument */ - arg->r_opt = -3; /* error */ - break; - } - else if( state == 4 ) { /* have an argument */ - if( in_alias ) { - if( !buffer ) - arg->r_opt = -6; - else { - char *p; - - buffer[i] = 0; - p = strpbrk( buffer, " \t" ); - if( p ) { - *p++ = 0; - trim_spaces( p ); - } - if( !p || !*p ) { - xfree( buffer ); - arg->r_opt = -10; - } - else { - store_alias( arg, buffer, p ); - } - } - } - else if( !(opts[idx].flags & 7) ) /* does not take an arg */ - arg->r_opt = -6; /* error */ - else { - char *p; - if( !buffer ) { - keyword[i] = 0; - buffer = xstrdup(keyword); - } - else - buffer[i] = 0; - - trim_spaces( buffer ); - p = buffer; - /* remove quotes if they totally enclose the - string, and do not occur within the string */ - if( *p == '"' && p[strlen(p)-1]=='"') { - char *p2=p; - - while(*(++p2)) - if(*p2=='"') - break; - - if(*p2=='"' && *(p2+1)=='\0') { - p[strlen(p)-1] = 0; - p++; - } - } - if( !set_opt_arg(arg, opts[idx].flags, p) ) - xfree(buffer); - } - break; - } - else if( c == EOF ) { - if( ferror(fp) ) - arg->r_opt = -5; /* read error */ - else - arg->r_opt = 0; /* eof */ - break; - } - state = 0; - i = 0; - } - else if( state == -1 ) - ; /* skip */ - else if( !state && isspace(c) ) - ; /* skip leading white space */ - else if( !state && c == '#' ) - state = 1; /* start of a comment */ - else if( state == 1 ) - ; /* skip comments */ - else if( state == 2 && isspace(c) ) { - 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 & 256)? -7:-2; - state = -1; /* skip rest of line and leave */ - } - } - else - state = 3; - } - else if( state == 3 ) { /* skip leading spaces of the argument */ - if( !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 { - buflen += 50; - buffer = xrealloc(buffer, buflen); - buffer[i++] = c; - } - } - else if( i < DIM(keyword)-1 ) - keyword[i++] = c; - else { - buflen = DIM(keyword)+50; - buffer = xmalloc(buflen); - memcpy(buffer, keyword, i); - buffer[i++] = c; - } - } - else if( i >= DIM(keyword)-1 ) { - arg->r_opt = -4; /* keyword to 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; - - /* 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 & (1<<4)) ) { /* skip the first entry */ - 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 & (1<<1)) ) { - arg->r_opt = -1; /* not an option but a argument */ - arg->r_type = 2; - arg->r.ret_str = s; - argc--; argv++; idx++; /* set to next one */ - } - else if( arg->internal.stopped ) { /* ready */ - arg->r_opt = 0; - goto leave; - } - else if( *s == '-' && s[1] == '-' ) { /* long option */ - char *argpos; - - arg->internal.inarg = 0; - if( !s[2] && !(arg->flags & (1<<3)) ) { /* 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) ) { - if( !(arg->flags & (1<<6)) ) { - show_help(opts, arg->flags); - } - } - else if( i < 0 && !strcmp( "version", s+2) ) { - if( !(arg->flags & (1<<6)) ) { - 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 ) /* ambiguous option */ - arg->r_opt = -8; - else if( i == -1 ) { - arg->r_opt = -2; - arg->r.ret_str = s+2; - } - else - arg->r_opt = opts[i].short_opt; - if( i < 0 ) - ; - else if( (opts[i].flags & 7) ) { - if( argpos ) { - s2 = argpos+1; - if( !*s2 ) - s2 = NULL; - } - else - s2 = argv[1]; - if( !s2 && (opts[i].flags & 8) ) { /* no argument but it is okay*/ - arg->r_type = 0; /* because it is optional */ - } - else if( !s2 ) { - arg->r_opt = -3; /* missing argument */ - } - else if( !argpos && *s2 == '-' && (opts[i].flags & 8) ) { - /* 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 = 0; - } - 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 = -6; /* argument not expected */ - 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 & (1<<5) ) { - 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 == '?' ) ) { - if( !(arg->flags & (1<<6)) ) { - show_help(opts, arg->flags); - } - } - - arg->r_opt = opts[i].short_opt; - if( !opts[i].short_opt ) { - arg->r_opt = (opts[i].flags & 256)? -7:-2; - 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 & 8) ) { /* no argument but it is okay*/ - arg->r_type = 0; /* because it is optional */ - } - else if( !s2 ) { - arg->r_opt = -3; /* missing argument */ - } - else if( *s2 == '-' && s2[1] && (opts[i].flags & 8) ) { - /* 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 = 0; - } - else { - set_opt_arg(arg, opts[i].flags, s2); - argc--; argv++; idx++; /* skip one */ - } - } - s = "x"; /* so that !s[1] yields false */ - } - else { /* does not take an argument */ - arg->r_type = 0; - 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 & (1<<2) ) { - arg->r_opt = -1; /* not an option but a argument */ - 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 1: /* takes int argument */ - arg->r.ret_int = (int)strtol(s,NULL,base); - return 0; - case 3: /* takes long argument */ - arg->r.ret_long= strtol(s,NULL,base); - return 0; - case 4: /* takes ulong argument */ - arg->r.ret_ulong= strtoul(s,NULL,base); - return 0; - case 2: /* takes string argument */ - 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; - - s=o->description+1; - if( *s != '=' ) - n++; - for(; *s && *s != '|'; s++ ) - 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 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 & 32 ) - puts("\n(A single dash may be used instead of the double ones)"); - } - if( (s=strusage(19)) ) { /* bug reports to ... */ - putchar('\n'); - 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 ); - /* 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( (const byte*)s, stdout); - fflush(stdout); -} - - -void -usage( int level ) -{ - if( !level ) { - fprintf(stderr,"%s %s; %s\n", strusage(11), strusage(13), - strusage(14) ); - fflush(stderr); - } - else if( level == 1 ) { - fputs(strusage(40),stderr); - exit(2); - } - else if( level == 2 ) { - puts(strusage(41)); - exit(0); - } -} - -/* Level - * 0: Copyright String auf stderr ausgeben - * 1: Kurzusage auf stderr ausgeben und beenden - * 2: Langusage auf stdout ausgeben und beenden - * 11: name of program - * 12: 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 * -default_strusage( int level ) -{ - const char *p = NULL; - switch( level ) { - case 11: p = "foo"; break; - case 13: p = "0.0"; break; - case 14: p = "Copyright (C) 2006 Free Software Foundation, Inc."; break; - case 15: p = -"This program comes with ABSOLUTELY NO WARRANTY.\n" -"This is free software, and you are welcome to redistribute it\n" -"under certain conditions. See the file COPYING for details.\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 2 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 program; if not, write to the Free Software\n" -"Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.\n"; - break; - case 40: /* short and long usage */ - case 41: p = ""; break; - } - - return p; -} - - - -#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[] = { - { 'v', "verbose", 0 , "Laut sein"}, - { 'e', "echo" , 0 , "Zeile ausgeben, damit wir sehen, was wir einegegeben haben"}, - { 'd', "debug", 0 , "Debug\nfalls mal etasws\nSchief geht"}, - { 'o', "output", 2 }, - { 'c', "cross-ref", 2|8, "cross-reference erzeugen\n" }, - { 'm', "my-option", 1|8 }, - { 500, "a-long-option", 0 }, - {0} }; - ARGPARSE_ARGS pargs = { &argc, &argv, 2|4|32 }; - int i; - - while( ArgParse( &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 = 1; break; /* force warning output */ - } - } - 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/util/assuan-buffer.c b/util/assuan-buffer.c deleted file mode 100644 index 3c0108601..000000000 --- a/util/assuan-buffer.c +++ /dev/null @@ -1,485 +0,0 @@ -/* assuan-buffer.c - read and send data - * Copyright (C) 2001, 2002, 2003, 2004 Free Software Foundation, Inc. - * - * This file is part of Assuan. - * - * Assuan 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. - * - * Assuan 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, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, - * USA. - */ - -/* Please note that this is a stripped down and modified version of - the orginal Assuan code from libassuan. */ - - -#include <config.h> -#include <stdlib.h> -#include <string.h> -#include <stdio.h> -#include <errno.h> -#include <unistd.h> -#include <assert.h> -#ifdef HAVE_W32_SYSTEM -#include <process.h> -#endif -#include "assuan-defs.h" - -#ifndef HAVE_MEMRCHR -void *memrchr(const void *s, int c, size_t n); -#endif - -static int -writen (assuan_context_t ctx, const char *buffer, size_t length) -{ - while (length) - { - ssize_t nwritten = ctx->io->writefnc (ctx, buffer, length); - - if (nwritten < 0) - { - if (errno == EINTR) - continue; - return -1; /* write error */ - } - length -= nwritten; - buffer += nwritten; - } - return 0; /* okay */ -} - -/* Read an entire line. */ -static int -readaline (assuan_context_t ctx, char *buf, size_t buflen, - int *r_nread, int *r_eof) -{ - size_t nleft = buflen; - char *p; - - *r_eof = 0; - *r_nread = 0; - while (nleft > 0) - { - ssize_t n = ctx->io->readfnc (ctx, buf, nleft); - - if (n < 0) - { - if (errno == EINTR) - continue; - return -1; /* read error */ - } - else if (!n) - { - *r_eof = 1; - break; /* allow incomplete lines */ - } - p = buf; - nleft -= n; - buf += n; - *r_nread += n; - - p = memrchr (p, '\n', n); - if (p) - break; /* at least one full line available - that's enough for now */ - } - - return 0; -} - - -int -_assuan_read_line (assuan_context_t ctx) -{ - char *line = ctx->inbound.line; - int nread, atticlen; - int rc; - char *endp = 0; - - if (ctx->inbound.eof) - return -1; - - atticlen = ctx->inbound.attic.linelen; - if (atticlen) - { - memcpy (line, ctx->inbound.attic.line, atticlen); - ctx->inbound.attic.linelen = 0; - - endp = memchr (line, '\n', atticlen); - if (endp) - /* Found another line in the attic. */ - { - rc = 0; - nread = atticlen; - atticlen = 0; - } - else - /* There is pending data but not a full line. */ - { - assert (atticlen < LINELENGTH); - rc = readaline (ctx, line + atticlen, - LINELENGTH - atticlen, &nread, &ctx->inbound.eof); - } - } - else - /* No pending data. */ - rc = readaline (ctx, line, LINELENGTH, - &nread, &ctx->inbound.eof); - if (rc) - { - if (ctx->log_fp) - fprintf (ctx->log_fp, "%s[%u.%p] DBG: <- [Error: %s]\n", - assuan_get_assuan_log_prefix (), - (unsigned int)getpid (), (void *)ctx, strerror (errno)); - return ASSUAN_Read_Error; - } - if (!nread) - { - assert (ctx->inbound.eof); - if (ctx->log_fp) - fprintf (ctx->log_fp, "%s[%u.%p] DBG: <- [EOF]\n", - assuan_get_assuan_log_prefix (), - (unsigned int)getpid (), (void *)ctx); - return -1; - } - - ctx->inbound.attic.pending = 0; - nread += atticlen; - - if (! endp) - endp = memchr (line, '\n', nread); - - if (endp) - { - int n = endp - line + 1; - if (n < nread) - /* LINE contains more than one line. We copy it to the attic - now as handlers are allowed to modify the passed - buffer. */ - { - int len = nread - n; - memcpy (ctx->inbound.attic.line, endp + 1, len); - ctx->inbound.attic.pending = memrchr (endp + 1, '\n', len) ? 1 : 0; - ctx->inbound.attic.linelen = len; - } - - if (endp != line && endp[-1] == '\r') - endp --; - *endp = 0; - - ctx->inbound.linelen = endp - line; - if (ctx->log_fp) - { - fprintf (ctx->log_fp, "%s[%u.%p] DBG: <- ", - assuan_get_assuan_log_prefix (), - (unsigned int)getpid (), (void *)ctx); - if (ctx->confidential) - fputs ("[Confidential data not shown]", ctx->log_fp); - else - _assuan_log_print_buffer (ctx->log_fp, - ctx->inbound.line, - ctx->inbound.linelen); - putc ('\n', ctx->log_fp); - } - return 0; - } - else - { - if (ctx->log_fp) - fprintf (ctx->log_fp, "%s[%u.%p] DBG: <- [Invalid line]\n", - assuan_get_assuan_log_prefix (), - (unsigned int)getpid (), (void *)ctx); - *line = 0; - ctx->inbound.linelen = 0; - return ctx->inbound.eof ? ASSUAN_Line_Not_Terminated - : ASSUAN_Line_Too_Long; - } -} - - -/* Read the next line from the client or server and return a pointer - in *LINE to a buffer holding the line. LINELEN is the length of - *LINE. The buffer is valid until the next read operation on it. - The caller may modify the buffer. The buffer is invalid (i.e. must - not be used) if an error is returned. - - Returns 0 on success or an assuan error code. - See also: assuan_pending_line(). -*/ -assuan_error_t -assuan_read_line (assuan_context_t ctx, char **line, size_t *linelen) -{ - assuan_error_t err; - - if (!ctx) - return ASSUAN_Invalid_Value; - - err = _assuan_read_line (ctx); - *line = ctx->inbound.line; - *linelen = ctx->inbound.linelen; - return err; -} - - -/* Return true if a full line is buffered (i.e. an entire line may be - read without any I/O). */ -int -assuan_pending_line (assuan_context_t ctx) -{ - return ctx && ctx->inbound.attic.pending; -} - - -assuan_error_t -_assuan_write_line (assuan_context_t ctx, const char *prefix, - const char *line, size_t len) -{ - int rc = 0; - size_t prefixlen = prefix? strlen (prefix):0; - - /* Make sure that the line is short enough. */ - if (len + prefixlen + 2 > ASSUAN_LINELENGTH) - { - if (ctx->log_fp) - fprintf (ctx->log_fp, "%s[%u.%p] DBG: -> " - "[supplied line too long -truncated]\n", - assuan_get_assuan_log_prefix (), - (unsigned int)getpid (), (void *)ctx); - if (prefixlen > 5) - prefixlen = 5; - if (len > ASSUAN_LINELENGTH - prefixlen - 2) - len = ASSUAN_LINELENGTH - prefixlen - 2 - 1; - } - - /* Fixme: we should do some kind of line buffering. */ - if (ctx->log_fp) - { - fprintf (ctx->log_fp, "%s[%u.%p] DBG: -> ", - assuan_get_assuan_log_prefix (), - (unsigned int)getpid (), (void *)ctx); - if (ctx->confidential) - fputs ("[Confidential data not shown]", ctx->log_fp); - else - _assuan_log_print_buffer (ctx->log_fp, line, len); - putc ('\n', ctx->log_fp); - } - - if (prefixlen) - { - rc = writen (ctx, prefix, prefixlen); - if (rc) - rc = ASSUAN_Write_Error; - } - if (!rc) - { - rc = writen (ctx, line, len); - if (rc) - rc = ASSUAN_Write_Error; - if (!rc) - { - rc = writen (ctx, "\n", 1); - if (rc) - rc = ASSUAN_Write_Error; - } - } - return rc; -} - - -assuan_error_t -assuan_write_line (assuan_context_t ctx, const char *line) -{ - size_t len; - const char *s; - - if (!ctx) - return ASSUAN_Invalid_Value; - - /* Make sure that we never take a LF from the user - this might - violate the protocol. */ - s = strchr (line, '\n'); - len = s? (s-line) : strlen (line); - - if (ctx->log_fp && s) - fprintf (ctx->log_fp, "%s[%u.%p] DBG: -> " - "[supplied line contained a LF -truncated]\n", - assuan_get_assuan_log_prefix (), - (unsigned int)getpid (), (void *)ctx); - - return _assuan_write_line (ctx, NULL, line, len); -} - - - -/* Write out the data in buffer as datalines with line wrapping and - percent escaping. This function is used for GNU's custom streams */ -int -_assuan_cookie_write_data (void *cookie, const char *buffer, size_t orig_size) -{ - assuan_context_t ctx = cookie; - size_t size = orig_size; - char *line; - size_t linelen; - - if (ctx->outbound.data.error) - return 0; - - line = ctx->outbound.data.line; - linelen = ctx->outbound.data.linelen; - line += linelen; - while (size) - { - /* insert data line header */ - if (!linelen) - { - *line++ = 'D'; - *line++ = ' '; - linelen += 2; - } - - /* copy data, keep some space for the CRLF and to escape one character */ - while (size && linelen < LINELENGTH-2-2) - { - if (*buffer == '%' || *buffer == '\r' || *buffer == '\n') - { - sprintf (line, "%%%02X", *(unsigned char*)buffer); - line += 3; - linelen += 3; - buffer++; - } - else - { - *line++ = *buffer++; - linelen++; - } - size--; - } - - if (linelen >= LINELENGTH-2-2) - { - if (ctx->log_fp) - { - fprintf (ctx->log_fp, "%s[%u.%p] DBG: -> ", - assuan_get_assuan_log_prefix (), - (unsigned int)getpid (), (void *)ctx); - - if (ctx->confidential) - fputs ("[Confidential data not shown]", ctx->log_fp); - else - _assuan_log_print_buffer (ctx->log_fp, - ctx->outbound.data.line, - linelen); - putc ('\n', ctx->log_fp); - } - *line++ = '\n'; - linelen++; - if (writen (ctx, ctx->outbound.data.line, linelen)) - { - ctx->outbound.data.error = ASSUAN_Write_Error; - return 0; - } - line = ctx->outbound.data.line; - linelen = 0; - } - } - - ctx->outbound.data.linelen = linelen; - return (int)orig_size; -} - - -/* Write out any buffered data - This function is used for GNU's custom streams */ -int -_assuan_cookie_write_flush (void *cookie) -{ - assuan_context_t ctx = cookie; - char *line; - size_t linelen; - - if (ctx->outbound.data.error) - return 0; - - line = ctx->outbound.data.line; - linelen = ctx->outbound.data.linelen; - line += linelen; - if (linelen) - { - if (ctx->log_fp) - { - fprintf (ctx->log_fp, "%s[%u.%p] DBG: -> ", - assuan_get_assuan_log_prefix (), - (unsigned int)getpid (), (void *)ctx); - if (ctx->confidential) - fputs ("[Confidential data not shown]", ctx->log_fp); - else - _assuan_log_print_buffer (ctx->log_fp, - ctx->outbound.data.line, linelen); - putc ('\n', ctx->log_fp); - } - *line++ = '\n'; - linelen++; - if (writen (ctx, ctx->outbound.data.line, linelen)) - { - ctx->outbound.data.error = ASSUAN_Write_Error; - return 0; - } - ctx->outbound.data.linelen = 0; - } - return 0; -} - - -/** - * assuan_send_data: - * @ctx: An assuan context - * @buffer: Data to send or NULL to flush - * @length: length of the data to send/ - * - * This function may be used by the server or the client to send data - * lines. The data will be escaped as required by the Assuan protocol - * and may get buffered until a line is full. To force sending the - * data out @buffer may be passed as NULL (in which case @length must - * also be 0); however when used by a client this flush operation does - * also send the terminating "END" command to terminate the reponse on - * a INQUIRE response. However, when assuan_transact() is used, this - * function takes care of sending END itself. - * - * Return value: 0 on success or an error code - **/ - -assuan_error_t -assuan_send_data (assuan_context_t ctx, const void *buffer, size_t length) -{ - if (!ctx) - return ASSUAN_Invalid_Value; - if (!buffer && length) - return ASSUAN_Invalid_Value; - - if (!buffer) - { /* flush what we have */ - _assuan_cookie_write_flush (ctx); - if (ctx->outbound.data.error) - return ctx->outbound.data.error; - if (!ctx->is_server) - return assuan_write_line (ctx, "END"); - } - else - { - _assuan_cookie_write_data (ctx, buffer, length); - if (ctx->outbound.data.error) - return ctx->outbound.data.error; - } - - return 0; -} - diff --git a/util/assuan-client.c b/util/assuan-client.c deleted file mode 100644 index 0467f6dc5..000000000 --- a/util/assuan-client.c +++ /dev/null @@ -1,282 +0,0 @@ -/* assuan-client.c - client functions - * Copyright (C) 2001, 2002 Free Software Foundation, Inc. - * Copyright (C) 2005 Free Software Foundation, Inc. - * - * This file is part of Assuan. - * - * Assuan 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. - * - * Assuan 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, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, - * USA. - */ - -/* Please note that this is a stripped down and modified version of - the orginal Assuan code from libassuan. */ - -#include <config.h> -#include <stdlib.h> -#include <stdio.h> -#include <errno.h> -#include <unistd.h> -#include <assert.h> -#include <string.h> - -#include "assuan-defs.h" - -#define xtoi_1(p) (*(p) <= '9'? (*(p)- '0'): \ - *(p) <= 'F'? (*(p)-'A'+10):(*(p)-'a'+10)) -#define xtoi_2(p) ((xtoi_1(p) * 16) + xtoi_1((p)+1)) - - -assuan_error_t -_assuan_read_from_server (assuan_context_t ctx, int *okay, int *off) -{ - char *line; - int linelen; - assuan_error_t rc; - - *okay = 0; - *off = 0; - do - { - rc = _assuan_read_line (ctx); - if (rc) - return rc; - line = ctx->inbound.line; - linelen = ctx->inbound.linelen; - } - while (*line == '#' || !linelen); - - if (linelen >= 1 - && line[0] == 'D' && line[1] == ' ') - { - *okay = 2; /* data line */ - *off = 2; - } - else if (linelen >= 1 - && line[0] == 'S' - && (line[1] == '\0' || line[1] == ' ')) - { - *okay = 4; - *off = 1; - while (line[*off] == ' ') - ++*off; - } - else if (linelen >= 2 - && line[0] == 'O' && line[1] == 'K' - && (line[2] == '\0' || line[2] == ' ')) - { - *okay = 1; - *off = 2; - while (line[*off] == ' ') - ++*off; - } - else if (linelen >= 3 - && line[0] == 'E' && line[1] == 'R' && line[2] == 'R' - && (line[3] == '\0' || line[3] == ' ')) - { - *okay = 0; - *off = 3; - while (line[*off] == ' ') - ++*off; - } - else if (linelen >= 7 - && line[0] == 'I' && line[1] == 'N' && line[2] == 'Q' - && line[3] == 'U' && line[4] == 'I' && line[5] == 'R' - && line[6] == 'E' - && (line[7] == '\0' || line[7] == ' ')) - { - *okay = 3; - *off = 7; - while (line[*off] == ' ') - ++*off; - } - else if (linelen >= 3 - && line[0] == 'E' && line[1] == 'N' && line[2] == 'D' - && (line[3] == '\0' || line[3] == ' ')) - { - *okay = 5; /* end line */ - *off = 3; - } - else - rc = ASSUAN_Invalid_Response; - return rc; -} - - - -assuan_error_t -assuan_transact (assuan_context_t ctx, - const char *command, - assuan_error_t (*data_cb)(void *, const void *, size_t), - void *data_cb_arg, - assuan_error_t (*inquire_cb)(void*, const char *), - void *inquire_cb_arg, - assuan_error_t (*status_cb)(void*, const char *), - void *status_cb_arg) -{ - return assuan_transact2 (ctx, command, - data_cb, data_cb_arg, - inquire_cb, inquire_cb_arg, - status_cb, status_cb_arg, - NULL, NULL); -} - - -/** - * assuan_transact2: - * @ctx: The Assuan context - * @command: Coimmand line to be send to server - * @data_cb: Callback function for data lines - * @data_cb_arg: first argument passed to @data_cb - * @inquire_cb: Callback function for a inquire response - * @inquire_cb_arg: first argument passed to @inquire_cb - * @status_cb: Callback function for a status response - * @status_cb_arg: first argument passed to @status_cb - * @okay_cb: Callback function for the final OK response - * @okay_cb_arg: first argument passed to @okay_cb - * - * FIXME: Write documentation - * - * Return value: 0 on success or error code. The error code may be - * the one one returned by the server in error lines or from the - * callback functions. - **/ -assuan_error_t -assuan_transact2 (assuan_context_t ctx, - const char *command, - assuan_error_t (*data_cb)(void *, const void *, size_t), - void *data_cb_arg, - assuan_error_t (*inquire_cb)(void*, const char *), - void *inquire_cb_arg, - assuan_error_t (*status_cb)(void*, const char *), - void *status_cb_arg, - assuan_error_t (*okay_cb)(void*, const char *), - void *okay_cb_arg) -{ - int rc, okay, off; - unsigned char *line; - int linelen; - - rc = assuan_write_line (ctx, command); - if (rc) - return rc; - - if (*command == '#' || !*command) - return 0; /* Don't expect a response for a comment line. */ - - again: - rc = _assuan_read_from_server (ctx, &okay, &off); - if (rc) - return rc; /* error reading from server */ - - line = ctx->inbound.line + off; - linelen = ctx->inbound.linelen - off; - - if (!okay) - { - rc = atoi (line); - if (rc < 100) - rc = ASSUAN_Server_Fault; - } - else if (okay == 1) /* Received OK. */ - { - if (okay_cb) - { - rc = okay_cb (okay_cb_arg, line); - /* We better wipe out the buffer after processing it. This - is no real guarantee that it won't get swapped out but at - least for the standard cases we can make sure that a - passphrase returned with the OK line is rendered - unreadable. In fact the current Assuan interface suffers - from the problem that it is not possible to do assuan I/O - through secure memory. There is no easy solution given - the current implementation but we need to address it - sooner or later. The problem was introduced with - gpg-agent's GET_PASPHRASE command but it might also make - sense to have a way to convey sessions keys through - secured memory. Note that the old implementation in gpg - for accessing the passphrase in fact used secure memory - but had the drawback of using a limited and not fully - conforming Assuan implementation - given that pinentry - and gpg-agent neither use secured memory for Assuan I/O, - it is negligible to drop the old implementation in gpg's - passphrase.c and use the wipememory workaround here. */ - memset (line, 0, strlen (line)); - } - } - else if (okay == 2) - { - if (!data_cb) - rc = ASSUAN_No_Data_Callback; - else - { - unsigned char *s, *d; - - for (s=d=line; linelen; linelen--) - { - if (*s == '%' && linelen > 2) - { /* handle escaping */ - s++; - *d++ = xtoi_2 (s); - s += 2; - linelen -= 2; - } - else - *d++ = *s++; - } - *d = 0; /* add a hidden string terminator */ - rc = data_cb (data_cb_arg, line, d - line); - if (!rc) - goto again; - } - } - else if (okay == 3) - { - if (!inquire_cb) - { - assuan_write_line (ctx, "END"); /* get out of inquire mode */ - _assuan_read_from_server (ctx, &okay, &off); /* dummy read */ - rc = ASSUAN_No_Inquire_Callback; - } - else - { - rc = inquire_cb (inquire_cb_arg, line); - if (!rc) - rc = assuan_send_data (ctx, NULL, 0); /* flush and send END */ - if (!rc) - goto again; - } - } - else if (okay == 4) - { - if (status_cb) - rc = status_cb (status_cb_arg, line); - if (!rc) - goto again; - } - else if (okay == 5) - { - if (!data_cb) - rc = ASSUAN_No_Data_Callback; - else - { - rc = data_cb (data_cb_arg, NULL, 0); - if (!rc) - goto again; - } - } - - return rc; -} - diff --git a/util/assuan-connect.c b/util/assuan-connect.c deleted file mode 100644 index 9952b4406..000000000 --- a/util/assuan-connect.c +++ /dev/null @@ -1,96 +0,0 @@ -/* assuan-connect.c - Establish a connection (client) - * Copyright (C) 2001, 2002 Free Software Foundation, Inc. - * - * This file is part of Assuan. - * - * Assuan 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. - * - * Assuan 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, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, - * USA. - */ - -/* Please note that this is a stripped down and modified version of - the orginal Assuan code from libassuan. */ - -#ifdef HAVE_CONFIG_H -#include <config.h> -#endif - -#include <stdlib.h> -#include <stdio.h> -#include <string.h> -#include <signal.h> -#include <unistd.h> -#include <errno.h> -#include <sys/types.h> -#ifndef HAVE_W32_SYSTEM -#include <sys/wait.h> -#endif - -#include "assuan-defs.h" - -/* Create a new context. */ -int -_assuan_new_context (assuan_context_t *r_ctx) -{ - assuan_context_t ctx; - - *r_ctx = NULL; - ctx = xcalloc (1, sizeof *ctx); - - ctx->input_fd = -1; - ctx->output_fd = -1; - - ctx->inbound.fd = -1; - ctx->outbound.fd = -1; - ctx->io = NULL; - - ctx->listen_fd = -1; - *r_ctx = ctx; - return 0; -} - - -void -_assuan_release_context (assuan_context_t ctx) -{ - if (ctx) - { - xfree (ctx->hello_line); - xfree (ctx->okay_line); - xfree (ctx); - } -} - - -/* Disconnect and release the context CTX. */ -void -assuan_disconnect (assuan_context_t ctx) -{ - if (ctx) - { - assuan_write_line (ctx, "BYE"); - ctx->finish_handler (ctx); - ctx->deinit_handler (ctx); - ctx->deinit_handler = NULL; - _assuan_release_context (ctx); - } -} - -/* Return the PID of the peer or -1 if not known. */ -pid_t -assuan_get_pid (assuan_context_t ctx) -{ - return (ctx && ctx->pid)? ctx->pid : -1; -} - diff --git a/util/assuan-defs.h b/util/assuan-defs.h deleted file mode 100644 index 67c4e13ce..000000000 --- a/util/assuan-defs.h +++ /dev/null @@ -1,244 +0,0 @@ -/* assuan-defs.c - Internal definitions to Assuan - * Copyright (C) 2001, 2002, 2004 Free Software Foundation, Inc. - * Copyright (C) 2005 Free Software Foundation, Inc. - * - * This file is part of Assuan. - * - * Assuan 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. - * - * Assuan 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, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, - * USA. - */ - -/* Please note that this is a stripped down and modified version of - the orginal Assuan code from libassuan. */ - - -#ifndef ASSUAN_DEFS_H -#define ASSUAN_DEFS_H - -#include <sys/types.h> -#ifndef HAVE_W32_SYSTEM -#include <sys/socket.h> -#include <sys/un.h> -#else -#include <windows.h> -#endif -#include <unistd.h> - -#include "assuan.h" -#include "memory.h" - -#ifndef HAVE_W32_SYSTEM -#define DIRSEP_C '/' -#else -#define DIRSEP_C '\\' -#endif - -#ifdef HAVE_W32_SYSTEM -#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. */ -}; - -/* Not needed anymore because the current mingw32 defines this in - sys/types.h */ -/* typedef int ssize_t; */ - -/* Missing W32 functions */ -int putc_unlocked (int c, FILE *stream); -void * memrchr (const void *block, int c, size_t size); -char * stpcpy (char *dest, const char *src); -#endif - -#define LINELENGTH ASSUAN_LINELENGTH - -struct cmdtbl_s -{ - const char *name; - int (*handler)(assuan_context_t, char *line); -}; - -struct assuan_io -{ - /* Routine to read from input_fd. */ - ssize_t (*readfnc) (assuan_context_t, void *, size_t); - /* Routine to write to output_fd. */ - ssize_t (*writefnc) (assuan_context_t, const void *, size_t); - /* Send a file descriptor. */ - assuan_error_t (*sendfd) (assuan_context_t, int); - /* Receive a file descriptor. */ - assuan_error_t (*receivefd) (assuan_context_t, int *); -}; - -struct assuan_context_s -{ - assuan_error_t err_no; - const char *err_str; - int os_errno; /* last system error number used with certain error codes*/ - - int confidential; - int is_server; /* set if this is context belongs to a server */ - int in_inquire; - char *hello_line; - char *okay_line; /* see assan_set_okay_line() */ - - void *user_pointer; /* for assuan_[gs]et_pointer () */ - - FILE *log_fp; - - struct { - int fd; - int eof; - char line[LINELENGTH]; - int linelen; /* w/o CR, LF - might not be the same as - strlen(line) due to embedded nuls. However a nul - is always written at this pos */ - struct { - char line[LINELENGTH]; - int linelen ; - int pending; /* i.e. at least one line is available in the attic */ - } attic; - } inbound; - - struct { - int fd; - struct { - FILE *fp; - char line[LINELENGTH]; - int linelen; - int error; - } data; - } outbound; - - int pipe_mode; /* We are in pipe mode, i.e. we can handle just one - connection and must terminate then */ - pid_t pid; /* The the pid of the peer. */ - int listen_fd; /* The fd we are listening on (used by socket servers) */ - int connected_fd; /* helper */ - - /* Used for Unix domain sockets. */ - struct sockaddr_un myaddr; - struct sockaddr_un serveraddr; - /* When reading from datagram sockets, we must read an entire - message at a time. This means that we have to do our own - buffering to be able to get the semantics of read. */ - void *domainbuffer; - /* Offset of start of buffer. */ - int domainbufferoffset; - /* Bytes buffered. */ - int domainbuffersize; - /* Memory allocated. */ - int domainbufferallocated; - - int *pendingfds; - int pendingfdscount; - - void (*deinit_handler)(assuan_context_t); - int (*accept_handler)(assuan_context_t); - int (*finish_handler)(assuan_context_t); - - struct cmdtbl_s *cmdtbl; - size_t cmdtbl_used; /* used entries */ - size_t cmdtbl_size; /* allocated size of table */ - - void (*bye_notify_fnc)(assuan_context_t); - void (*reset_notify_fnc)(assuan_context_t); - void (*cancel_notify_fnc)(assuan_context_t); - int (*option_handler_fnc)(assuan_context_t,const char*, const char*); - void (*input_notify_fnc)(assuan_context_t, const char *); - void (*output_notify_fnc)(assuan_context_t, const char *); - - int input_fd; /* set by INPUT command */ - int output_fd; /* set by OUTPUT command */ - - /* io routines. */ - struct assuan_io *io; -}; - -/*-- assuan-pipe-server.c --*/ -int _assuan_new_context (assuan_context_t *r_ctx); -void _assuan_release_context (assuan_context_t ctx); - -/*-- assuan-domain-connect.c --*/ -/* Make a connection to the Unix domain socket NAME and return a new - Assuan context in CTX. SERVER_PID is currently not used but may - become handy in the future. */ -assuan_error_t _assuan_domain_init (assuan_context_t *r_ctx, - int rendezvousfd, - pid_t peer); - -/*-- assuan-handler.c --*/ -int _assuan_register_std_commands (assuan_context_t ctx); - -/*-- assuan-buffer.c --*/ -int _assuan_read_line (assuan_context_t ctx); -int _assuan_cookie_write_data (void *cookie, const char *buffer, size_t size); -int _assuan_cookie_write_flush (void *cookie); -assuan_error_t _assuan_write_line (assuan_context_t ctx, const char *prefix, - const char *line, size_t len); - -/*-- assuan-client.c --*/ -assuan_error_t _assuan_read_from_server (assuan_context_t ctx, int *okay, int *off); - - -/*-- assuan-util.c --*/ - -#define set_error(c,e,t) assuan_set_error ((c), ASSUAN_ ## e, (t)) - -void _assuan_log_print_buffer (FILE *fp, const void *buffer, size_t length); -void _assuan_log_sanitized_string (const char *string); - -#ifdef HAVE_W32_SYSTEM -const char *_assuan_w32_strerror (int ec); -#define w32_strerror(e) _assuan_w32_strerror ((e)) -#endif /*HAVE_W32_SYSTEM*/ - - -/*-- assuan-logging.c --*/ -void _assuan_set_default_log_stream (FILE *fp); - -void _assuan_log_printf (const char *format, ...) -#if __GNUC__ > 2 || (__GNUC__ == 2 && __GNUC_MINOR__ >= 5 ) - __attribute__ ((format (printf,1,2))) -#endif - ; - -/*-- assuan-io.c --*/ -ssize_t _assuan_simple_read (assuan_context_t ctx, void *buffer, size_t size); -ssize_t _assuan_simple_write (assuan_context_t ctx, const void *buffer, - size_t size); - -/*-- assuan-socket.c --*/ -int _assuan_close (int fd); -int _assuan_sock_new (int domain, int type, int proto); -int _assuan_sock_connect (int sockfd, struct sockaddr *addr, int addrlen); - -#ifdef HAVE_FOPENCOOKIE -/* We have to implement funopen in terms of glibc's fopencookie. */ -FILE *_assuan_funopen(void *cookie, - cookie_read_function_t *readfn, - cookie_write_function_t *writefn, - cookie_seek_function_t *seekfn, - cookie_close_function_t *closefn); -#define funopen(a,r,w,s,c) _assuan_funopen ((a), (r), (w), (s), (c)) -#endif /*HAVE_FOPENCOOKIE*/ - -#endif /*ASSUAN_DEFS_H*/ - diff --git a/util/assuan-errors.c b/util/assuan-errors.c deleted file mode 100644 index c3a8770cb..000000000 --- a/util/assuan-errors.c +++ /dev/null @@ -1,105 +0,0 @@ -/* assuan-errors.c - error codes - * Copyright (C) 2001, 2002, 2003 Free Software Foundation, Inc. - * Copyright (C) 2005 Free Software Foundation, Inc. - * - * This file is part of Assuan. - * - * Assuan 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. - * - * Assuan 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, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, - * USA. - */ - -/* Please note that this is a stripped down and modified version of - the orginal Assuan code from libassuan. */ - -#include <stdio.h> -#include "assuan.h" - -/* This function returns a textual representaion of the given error - code. If this is an unknown value, a string with the value is - returned (Beware: it is hold in a static buffer). Return value: - String with the error description. - */ -const char * -assuan_strerror (assuan_error_t err) -{ - const char *s; - static char buf[50]; - - switch (err) - { - case ASSUAN_No_Error: s="no error"; break; - case ASSUAN_General_Error: s="general error"; break; - case ASSUAN_Out_Of_Core: s="out of core"; break; - case ASSUAN_Invalid_Value: s="invalid value"; break; - case ASSUAN_Timeout: s="timeout"; break; - case ASSUAN_Read_Error: s="read error"; break; - case ASSUAN_Write_Error: s="write error"; break; - case ASSUAN_Problem_Starting_Server: s="problem starting server"; break; - case ASSUAN_Not_A_Server: s="not a server"; break; - case ASSUAN_Not_A_Client: s="not a client"; break; - case ASSUAN_Nested_Commands: s="nested commands"; break; - case ASSUAN_Invalid_Response: s="invalid response"; break; - case ASSUAN_No_Data_Callback: s="no data callback"; break; - case ASSUAN_No_Inquire_Callback: s="no inquire callback"; break; - case ASSUAN_Connect_Failed: s="connect failed"; break; - case ASSUAN_Accept_Failed: s="accept failed"; break; - case ASSUAN_Not_Implemented: s="not implemented"; break; - case ASSUAN_Server_Fault: s="server fault"; break; - case ASSUAN_Invalid_Command: s="invalid command"; break; - case ASSUAN_Unknown_Command: s="unknown command"; break; - case ASSUAN_Syntax_Error: s="syntax error"; break; - case ASSUAN_Parameter_Error: s="parameter error"; break; - case ASSUAN_Parameter_Conflict: s="parameter conflict"; break; - case ASSUAN_Line_Too_Long: s="line too long"; break; - case ASSUAN_Line_Not_Terminated: s="line not terminated"; break; - case ASSUAN_No_Input: s="no input"; break; - case ASSUAN_No_Output: s="no output"; break; - case ASSUAN_Canceled: s="canceled"; break; - case ASSUAN_Unsupported_Algorithm: s="unsupported algorithm"; break; - case ASSUAN_Server_Resource_Problem: s="server resource problem"; break; - case ASSUAN_Server_IO_Error: s="server io error"; break; - case ASSUAN_Server_Bug: s="server bug"; break; - case ASSUAN_No_Data_Available: s="no data available"; break; - case ASSUAN_Invalid_Data: s="invalid data"; break; - case ASSUAN_Unexpected_Command: s="unexpected command"; break; - case ASSUAN_Too_Much_Data: s="too much data"; break; - case ASSUAN_Inquire_Unknown: s="inquire unknown"; break; - case ASSUAN_Inquire_Error: s="inquire error"; break; - case ASSUAN_Invalid_Option: s="invalid option"; break; - case ASSUAN_Invalid_Index: s="invalid index"; break; - case ASSUAN_Unexpected_Status: s="unexpected status"; break; - case ASSUAN_Unexpected_Data: s="unexpected data"; break; - case ASSUAN_Invalid_Status: s="invalid status"; break; - case ASSUAN_Locale_Problem: s="locale problem"; break; - case ASSUAN_Not_Confirmed: s="not confirmed"; break; - case ASSUAN_USER_ERROR_FIRST: s="user error first"; break; - case ASSUAN_USER_ERROR_LAST: s="user error last"; break; - default: - { - unsigned int source, code; - - source = ((err >> 24) & 0xff); - code = (err & 0x00ffffff); - if (source) /* Assume this is an libgpg-error. */ - sprintf (buf, "ec=%u.%u", source, code ); - else - sprintf (buf, "ec=%d", err ); - s=buf; break; - } - } - - return s; -} - diff --git a/util/assuan-logging.c b/util/assuan-logging.c deleted file mode 100644 index f2d6c876d..000000000 --- a/util/assuan-logging.c +++ /dev/null @@ -1,116 +0,0 @@ -/* assuan-logging.c - Default logging function. - * Copyright (C) 2002, 2003, 2004 Free Software Foundation, Inc. - * - * This file is part of Assuan. - * - * Assuan 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. - * - * Assuan 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, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, - * USA. - */ - -/* Please note that this is a stripped down and modified version of - the orginal Assuan code from libassuan. */ - -#ifdef HAVE_CONFIG_H -#include <config.h> -#endif -#include <stdio.h> -#include <string.h> -#include <stdarg.h> -#ifdef HAVE_W32_SYSTEM -#include <windows.h> -#endif /*HAVE_W32_SYSTEM*/ - -#include "assuan-defs.h" - -static char prefix_buffer[80]; -static FILE *_assuan_log; - -void -_assuan_set_default_log_stream (FILE *fp) -{ - if (!_assuan_log) - _assuan_log = fp; -} - -void -assuan_set_assuan_log_stream (FILE *fp) -{ - _assuan_log = fp; -} - -FILE * -assuan_get_assuan_log_stream (void) -{ - return _assuan_log ? _assuan_log : stderr; -} - - -/* Set the prefix to be used for logging to TEXT or - resets it to the default if TEXT is NULL. */ -void -assuan_set_assuan_log_prefix (const char *text) -{ - if (text) - { - strncpy (prefix_buffer, text, sizeof (prefix_buffer)-1); - prefix_buffer[sizeof (prefix_buffer)-1] = 0; - } - else - *prefix_buffer = 0; -} - -const char * -assuan_get_assuan_log_prefix (void) -{ - return prefix_buffer; -} - - -void -_assuan_log_printf (const char *format, ...) -{ - va_list arg_ptr; - FILE *fp; - const char *prf; - - fp = assuan_get_assuan_log_stream (); - prf = assuan_get_assuan_log_prefix (); - if (*prf) - { - fputs (prf, fp); - fputs (": ", fp); - } - - va_start (arg_ptr, format); - vfprintf (fp, format, arg_ptr ); - va_end (arg_ptr); -} - - - -#ifdef HAVE_W32_SYSTEM -const char * -_assuan_w32_strerror (int ec) -{ - static char strerr[256]; - - if (ec == -1) - ec = (int)GetLastError (); - FormatMessage (FORMAT_MESSAGE_FROM_SYSTEM, NULL, ec, - MAKELANGID (LANG_NEUTRAL, SUBLANG_DEFAULT), - strerr, sizeof (strerr)-1, NULL); - return strerr; -} -#endif /*HAVE_W32_SYSTEM*/ diff --git a/util/assuan-socket-connect.c b/util/assuan-socket-connect.c deleted file mode 100644 index 0c580cd5f..000000000 --- a/util/assuan-socket-connect.c +++ /dev/null @@ -1,191 +0,0 @@ -/* assuan-socket-connect.c - Assuan socket based client - * Copyright (C) 2002, 2003, 2004 Free Software Foundation, Inc. - * - * This file is part of Assuan. - * - * Assuan 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. - * - * Assuan 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, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, - * USA. - */ - -/* Please note that this is a stripped down and modified version of - the orginal Assuan code from libassuan. */ - -#include <config.h> -#include <stdlib.h> -#include <stddef.h> -#include <stdio.h> -#include <string.h> -#include <errno.h> -#include <unistd.h> -#include <sys/types.h> -#ifndef HAVE_W32_SYSTEM -#include <sys/socket.h> -#include <sys/un.h> -#else -#include <windows.h> -#endif - -#include "assuan-defs.h" - -/* Hacks for Slowaris. */ -#ifndef PF_LOCAL -# ifdef PF_UNIX -# define PF_LOCAL PF_UNIX -# else -# define PF_LOCAL AF_UNIX -# endif -#endif -#ifndef AF_LOCAL -# define AF_LOCAL AF_UNIX -#endif - -#ifndef SUN_LEN -# define SUN_LEN(ptr) ((size_t) (((struct sockaddr_un *) 0)->sun_path) \ - + strlen ((ptr)->sun_path)) -#endif - - -static int -do_finish (assuan_context_t ctx) -{ - if (ctx->inbound.fd != -1) - { - _assuan_close (ctx->inbound.fd); - } - ctx->inbound.fd = -1; - ctx->outbound.fd = -1; - return 0; -} - -static void -do_deinit (assuan_context_t ctx) -{ - do_finish (ctx); -} - - -static ssize_t -simple_read (assuan_context_t ctx, void *buffer, size_t size) -{ -#ifndef HAVE_W32_SYSTEM - return read (ctx->inbound.fd, buffer, size); -#else - return recv (ctx->inbound.fd, buffer, size, 0); -#endif -} - -static ssize_t -simple_write (assuan_context_t ctx, const void *buffer, size_t size) -{ -#ifndef HAVE_W32_SYSTEM - return write (ctx->outbound.fd, buffer, size); -#else - return send (ctx->outbound.fd, buffer, size, 0); -#endif -} - - -/* Make a connection to the Unix domain socket NAME and return a new - Assuan context in CTX. SERVER_PID is currently not used but may - become handy in the future. */ -assuan_error_t -assuan_socket_connect (assuan_context_t *r_ctx, - const char *name, pid_t server_pid) -{ - static struct assuan_io io = { simple_read, simple_write }; - - assuan_error_t err; - assuan_context_t ctx; - int fd; - struct sockaddr_un srvr_addr; - size_t len; - const char *s; - - if (!r_ctx || !name) - return ASSUAN_Invalid_Value; - *r_ctx = NULL; - - /* We require that the name starts with a slash, so that we can - alter reuse this function for other socket types. To make things - easier we allow an optional dirver prefix. */ - s = name; - if (*s && s[1] == ':') - s += 2; - if (*s != DIRSEP_C && *s != '/') - return ASSUAN_Invalid_Value; - - if (strlen (name)+1 >= sizeof srvr_addr.sun_path) - return ASSUAN_Invalid_Value; - - err = _assuan_new_context (&ctx); - if (err) - return err; - ctx->deinit_handler = do_deinit; - ctx->finish_handler = do_finish; - - - fd = _assuan_sock_new (PF_LOCAL, SOCK_STREAM, 0); - if (fd == -1) - { - _assuan_log_printf ("can't create socket: %s\n", strerror (errno)); - _assuan_release_context (ctx); - return ASSUAN_General_Error; - } - - memset (&srvr_addr, 0, sizeof srvr_addr); - srvr_addr.sun_family = AF_LOCAL; - strncpy (srvr_addr.sun_path, name, sizeof (srvr_addr.sun_path) - 1); - srvr_addr.sun_path[sizeof (srvr_addr.sun_path) - 1] = 0; - len = SUN_LEN (&srvr_addr); - - - if (_assuan_sock_connect (fd, (struct sockaddr *) &srvr_addr, len) == -1) - { - _assuan_log_printf ("can't connect to `%s': %s\n", - name, strerror (errno)); - _assuan_release_context (ctx); - _assuan_close (fd); - return ASSUAN_Connect_Failed; - } - - ctx->inbound.fd = fd; - ctx->outbound.fd = fd; - ctx->io = &io; - - /* initial handshake */ - { - int okay, off; - - err = _assuan_read_from_server (ctx, &okay, &off); - if (err) - _assuan_log_printf ("can't connect to server: %s\n", - assuan_strerror (err)); - else if (okay != 1) - { - /*LOG ("can't connect to server: `");*/ - _assuan_log_sanitized_string (ctx->inbound.line); - fprintf (assuan_get_assuan_log_stream (), "'\n"); - err = ASSUAN_Connect_Failed; - } - } - - if (err) - { - assuan_disconnect (ctx); - } - else - *r_ctx = ctx; - return 0; -} diff --git a/util/assuan-socket.c b/util/assuan-socket.c deleted file mode 100644 index 4d79792ce..000000000 --- a/util/assuan-socket.c +++ /dev/null @@ -1,97 +0,0 @@ -/* assuan-socket.c - * Copyright (C) 2004 Free Software Foundation, Inc. - * - * This file is part of GnuPG. - * - * GnuPG is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * GnuPG is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, - * USA. - */ - -/* Please note that this is a stripped down and modified version of - the orginal Assuan code from libassuan. */ - -#include <config.h> -#include <stdio.h> -#ifdef HAVE_W32_SYSTEM -#include <windows.h> -#include <io.h> -#else -#include <sys/types.h> -#include <sys/socket.h> -#endif -#include "assuan-defs.h" - -int -_assuan_close (int fd) -{ -#ifndef HAVE_W32_SYSTEM - return close (fd); -#else - int rc = closesocket (fd); - if (rc && WSAGetLastError () == WSAENOTSOCK) - rc = close (fd); - return rc; -#endif -} - - -int -_assuan_sock_new (int domain, int type, int proto) -{ -#ifndef HAVE_W32_SYSTEM - return socket (domain, type, proto); -#else - if (domain == AF_UNIX || domain == AF_LOCAL) - domain = AF_INET; - return socket (domain, type, proto); -#endif -} - - -int -_assuan_sock_connect (int sockfd, struct sockaddr * addr, int addrlen) -{ -#ifndef HAVE_W32_SYSTEM - return connect (sockfd, addr, addrlen); -#else - struct sockaddr_in myaddr; - struct sockaddr_un * unaddr; - FILE * fp; - int port = 0; - - unaddr = (struct sockaddr_un *)addr; - fp = fopen (unaddr->sun_path, "rb"); - if (!fp) - return -1; - fscanf (fp, "%d", &port); - fclose (fp); - /* XXX: set errno in this case */ - if (port < 0 || port > 65535) - return -1; - - myaddr.sin_family = AF_INET; - myaddr.sin_port = port; - myaddr.sin_addr.s_addr = htonl (INADDR_LOOPBACK); - - /* we need this later. */ - unaddr->sun_family = myaddr.sin_family; - unaddr->sun_port = myaddr.sin_port; - unaddr->sun_addr.s_addr = myaddr.sin_addr.s_addr; - - return connect (sockfd, (struct sockaddr *)&myaddr, sizeof myaddr); -#endif -} - - diff --git a/util/assuan-util.c b/util/assuan-util.c deleted file mode 100644 index db3cb7232..000000000 --- a/util/assuan-util.c +++ /dev/null @@ -1,171 +0,0 @@ -/* assuan-util.c - Utility functions for Assuan - * Copyright (C) 2001, 2002, 2003, 2004 Free Software Foundation, Inc. - * Copyright (C) 2005 Free Software Foundation, Inc. - * - * This file is part of Assuan. - * - * Assuan 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. - * - * Assuan 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, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, - * USA. - */ - -/* Please note that this is a stripped down and modified version of - the orginal Assuan code from libassuan. */ - -#include <config.h> -#include <stdlib.h> -#include <stdio.h> -#include <string.h> -#include <ctype.h> - -#include "assuan-defs.h" - - - -/* Store the error in the context so that the error sending function - can take out a descriptive text. Inside the assuan code, use the - macro set_error instead of this function. */ -int -assuan_set_error (assuan_context_t ctx, int err, const char *text) -{ - ctx->err_no = err; - ctx->err_str = text; - return err; -} - -void -assuan_set_pointer (assuan_context_t ctx, void *pointer) -{ - if (ctx) - ctx->user_pointer = pointer; -} - -void * -assuan_get_pointer (assuan_context_t ctx) -{ - return ctx? ctx->user_pointer : NULL; -} - - -void -assuan_set_log_stream (assuan_context_t ctx, FILE *fp) -{ - if (ctx) - { - if (ctx->log_fp) - fflush (ctx->log_fp); - ctx->log_fp = fp; - _assuan_set_default_log_stream (fp); - } -} - - -void -assuan_begin_confidential (assuan_context_t ctx) -{ - if (ctx) - { - ctx->confidential = 1; - } -} - -void -assuan_end_confidential (assuan_context_t ctx) -{ - if (ctx) - { - ctx->confidential = 0; - } -} - -/* Dump a possibly binary string (used for debugging). Distinguish - ascii text from binary and print it accordingly. */ -void -_assuan_log_print_buffer (FILE *fp, const void *buffer, size_t length) -{ - const unsigned char *s; - int n; - - for (n=length,s=buffer; n; n--, s++) - if ((!isascii (*s) || iscntrl (*s) || !isprint (*s)) && !(*s >= 0x80)) - break; - - s = buffer; - if (!n && *s != '[') - fwrite (buffer, length, 1, fp); - else - { - putc ('[', fp); - for (n=0; n < length; n++, s++) - fprintf (fp, " %02x", *s); - putc (' ', fp); - putc (']', fp); - } -} - -/* Log a user supplied string. Escapes non-printable before - printing. */ -void -_assuan_log_sanitized_string (const char *string) -{ - const unsigned char *s = string; - FILE *fp = assuan_get_assuan_log_stream (); - - if (! *s) - return; - - for (; *s; s++) - { - int c = 0; - - switch (*s) - { - case '\r': - c = 'r'; - break; - - case '\n': - c = 'n'; - break; - - case '\f': - c = 'f'; - break; - - case '\v': - c = 'v'; - break; - - case '\b': - c = 'b'; - break; - - default: - if ((isascii (*s) && isprint (*s)) || (*s >= 0x80)) - putc (*s, fp); - else - { - putc ('\\', fp); - fprintf (fp, "x%02x", *s); - } - } - - if (c) - { - putc ('\\', fp); - putc (c, fp); - } - } -} - diff --git a/util/cert.c b/util/cert.c deleted file mode 100644 index 1b3390b80..000000000 --- a/util/cert.c +++ /dev/null @@ -1,251 +0,0 @@ -/* cert.c - DNS CERT code - * Copyright (C) 2005, 2006 Free Software Foundation, Inc. - * - * This file is part of GNUPG. - * - * GNUPG is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * GNUPG is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, - * USA. - */ - -#include <config.h> -#include <sys/types.h> -#ifdef USE_DNS_CERT -#ifdef _WIN32 -#include <windows.h> -#else -#include <netinet/in.h> -#include <arpa/nameser.h> -#include <resolv.h> -#endif -#include <string.h> -#include "memory.h" -#endif -#include "iobuf.h" -#include "util.h" - -/* Not every installation has gotten around to supporting CERTs - yet... */ -#ifndef T_CERT -#define T_CERT 37 -#endif - -#ifdef USE_DNS_CERT - -/* Returns -1 on error, 0 for no answer, 1 for PGP provided and 2 for - IPGP provided. */ -int -get_cert(const char *name,size_t max_size,IOBUF *iobuf, - unsigned char **fpr,size_t *fpr_len,char **url) -{ - unsigned char *answer; - int r,ret=-1; - u16 count; - - if(fpr) - *fpr=NULL; - - if(url) - *url=NULL; - - answer=xmalloc(max_size); - - r=res_query(name,C_IN,T_CERT,answer,max_size); - /* Not too big, not too small, no errors and at least 1 answer. */ - if(r>=sizeof(HEADER) && r<=max_size - && (((HEADER *)answer)->rcode)==NOERROR - && (count=ntohs(((HEADER *)answer)->ancount))) - { - int rc; - unsigned char *pt,*emsg; - - emsg=&answer[r]; - - pt=&answer[sizeof(HEADER)]; - - /* Skip over the query */ - - rc=dn_skipname(pt,emsg); - if(rc==-1) - goto fail; - - pt+=rc+QFIXEDSZ; - - /* There are several possible response types for a CERT request. - We're interested in the PGP (a key) and IPGP (a URI) types. - Skip all others. TODO: A key is better than a URI since - we've gone through all this bother to fetch it, so favor that - if we have both PGP and IPGP? */ - - while(count-->0 && pt<emsg) - { - u16 type,class,dlen,ctype; - - rc=dn_skipname(pt,emsg); /* the name we just queried for */ - if(rc==-1) - break; - - pt+=rc; - - /* Truncated message? 15 bytes takes us to the point where - we start looking at the ctype. */ - if((emsg-pt)<15) - break; - - type=*pt++ << 8; - type|=*pt++; - - class=*pt++ << 8; - class|=*pt++; - /* We asked for IN and got something else !? */ - if(class!=C_IN) - break; - - /* ttl */ - pt+=4; - - /* data length */ - dlen=*pt++ << 8; - dlen|=*pt++; - - /* We asked for CERT and got something else - might be a - CNAME, so loop around again. */ - if(type!=T_CERT) - { - pt+=dlen; - continue; - } - - /* The CERT type */ - ctype=*pt++ << 8; - ctype|=*pt++; - - /* Skip the CERT key tag and algo which we don't need. */ - pt+=3; - - dlen-=5; - - /* 15 bytes takes us to here */ - - if(ctype==3 && iobuf && dlen) - { - /* PGP type */ - *iobuf=iobuf_temp_with_content((char *)pt,dlen); - ret=1; - break; - } - else if(ctype==6 && dlen && dlen<1023 && dlen>=pt[0]+1 - && fpr && fpr_len && url) - { - /* IPGP type */ - *fpr_len=pt[0]; - - if(*fpr_len) - { - *fpr=xmalloc(*fpr_len); - memcpy(*fpr,&pt[1],*fpr_len); - } - else - *fpr=NULL; - - if(dlen>*fpr_len+1) - { - *url=xmalloc(dlen-(*fpr_len+1)+1); - memcpy(*url,&pt[*fpr_len+1],dlen-(*fpr_len+1)); - (*url)[dlen-(*fpr_len+1)]='\0'; - } - else - *url=NULL; - - ret=2; - break; - } - - /* Neither type matches, so go around to the next answer. */ - pt+=dlen; - } - } - - fail: - xfree(answer); - - return ret; -} - -#else /* !USE_DNS_CERT */ - -int -get_cert(const char *name,size_t max_size,IOBUF *iobuf, - unsigned char **fpr,size_t *fpr_len,char **url) -{ - return -1; -} - -#endif - -/* Test with simon.josefsson.org */ - -#ifdef TEST -int -main(int argc,char *argv[]) -{ - unsigned char *fpr; - size_t fpr_len; - char *url; - int rc; - IOBUF iobuf; - - if(argc!=2) - { - printf("cert-test [name]\n"); - return 1; - } - - printf("CERT lookup on %s\n",argv[1]); - - rc=get_cert(argv[1],16384,&iobuf,&fpr,&fpr_len,&url); - if(rc==-1) - printf("error\n"); - else if(rc==0) - printf("no answer\n"); - else if(rc==1) - { - printf("key found: %d bytes\n",(int)iobuf_get_temp_length(iobuf)); - iobuf_close(iobuf); - } - else if(rc==2) - { - if(fpr) - { - size_t i; - printf("Fingerprint found (%d bytes): ",(int)fpr_len); - for(i=0;i<fpr_len;i++) - printf("%02X",fpr[i]); - printf("\n"); - } - else - printf("No fingerprint found\n"); - - if(url) - printf("URL found: %s\n",url); - else - printf("No URL found\n"); - - xfree(fpr); - xfree(url); - } - - return 0; -} -#endif /* TEST */ diff --git a/util/dotlock.c b/util/dotlock.c deleted file mode 100644 index 9edac57ed..000000000 --- a/util/dotlock.c +++ /dev/null @@ -1,454 +0,0 @@ -/* dotlock.c - dotfile locking - * Copyright (C) 1998, 1999, 2000, 2001, 2004, - * 2005 Free Software Foundation, Inc. - * - * This file is part of GnuPG. - * - * GnuPG is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * GnuPG is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, - * USA. - */ - -#include <config.h> -#include <stdlib.h> -#include <string.h> -#include <errno.h> -#include <ctype.h> -#include <errno.h> -#include <unistd.h> -#if !defined (HAVE_DOSISH_SYSTEM) -#include <sys/utsname.h> -#endif -#include <sys/types.h> -#ifndef _WIN32 -#include <sys/time.h> -#endif -#include <sys/stat.h> -#include <fcntl.h> -#include <signal.h> -#include "types.h" -#include "util.h" -#include "memory.h" - -struct dotlock_handle { - struct dotlock_handle *next; - char *tname; /* name of lockfile template */ - char *lockname; /* name of the real lockfile */ - int locked; /* lock status */ - int disable; /* locking */ -}; - - -static volatile DOTLOCK all_lockfiles; -static int never_lock; - -void -disable_dotlock(void) -{ - never_lock = 1; -} - -/**************** - * Create a lockfile with the given name and return an object of - * type DOTLOCK which may be used later to actually do the lock. - * A cleanup routine gets installed to cleanup left over locks - * or other files used together with the lockmechanism. - * Althoug the function is called dotlock, this does not necessarily - * mean that real lockfiles are used - the function may decide to - * use fcntl locking. Calling the function with NULL only install - * the atexit handler and maybe used to assure that the cleanup - * is called after all other atexit handlers. - * - * Notes: This function creates a lock file in the same directory - * as file_to_lock with the name "file_to_lock.lock" - * A temporary file ".#lk.<hostname>.pid[.threadid] is used. - * This function does nothing for Windoze. - */ -DOTLOCK -create_dotlock( const char *file_to_lock ) -{ - static int initialized; - DOTLOCK h; -#if !defined (HAVE_DOSISH_SYSTEM) - int fd = -1; - char pidstr[16]; - struct utsname utsbuf; - const char *nodename; - const char *dirpart; - int dirpartlen; -#endif - - if( !initialized ) { - atexit( remove_lockfiles ); - initialized = 1; - } - if( !file_to_lock ) - return NULL; - - h = xmalloc_clear( sizeof *h ); - if( never_lock ) { - h->disable = 1; -#ifdef _REENTRANT - /* fixme: aquire mutex on all_lockfiles */ -#endif - h->next = all_lockfiles; - all_lockfiles = h; - return h; - } - - -#if !defined (HAVE_DOSISH_SYSTEM) - sprintf( pidstr, "%10d\n", (int)getpid() ); - /* fixme: add the hostname to the second line (FQDN or IP addr?) */ - - /* 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; - - h->tname = xmalloc( dirpartlen + 6+30+ strlen(nodename) + 11 ); -#ifndef __riscos__ - sprintf( h->tname, "%.*s/.#lk%p.%s.%d", - dirpartlen, dirpart, (void *)h, nodename, (int)getpid() ); -#else /* __riscos__ */ - sprintf( h->tname, "%.*s.lk%p/%s/%d", - dirpartlen, dirpart, (void *)h, nodename, (int)getpid() ); -#endif /* __riscos__ */ - - do { - 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)); - xfree(h->tname); - xfree(h); - return NULL; - } - if( write(fd, pidstr, 11 ) != 11 ) { - all_lockfiles = h->next; -#ifdef _REENTRANT - /* release mutex */ -#endif - log_fatal( "error writing to `%s': %s\n", h->tname, strerror(errno) ); - close(fd); - unlink(h->tname); - xfree(h->tname); - xfree(h); - return NULL; - } - if( close(fd) ) { - all_lockfiles = h->next; -#ifdef _REENTRANT - /* release mutex */ -#endif - log_error( "error closing `%s': %s\n", h->tname, strerror(errno)); - unlink(h->tname); - xfree(h->tname); - xfree(h); - return NULL; - } - -#ifdef _REENTRANT - /* release mutex */ -#endif -#endif - h->lockname = xmalloc( strlen(file_to_lock) + 6 ); - strcpy(stpcpy(h->lockname, file_to_lock), EXTSEP_S "lock"); - return h; -} - - -void -destroy_dotlock ( DOTLOCK h ) -{ -#if !defined (HAVE_DOSISH_SYSTEM) - if ( h ) - { - DOTLOCK hprev, htmp; - - /* 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; - } - - /* Second destroy the lock. */ - if (!h->disable) - { - if (h->locked && h->lockname) - unlink (h->lockname); - if (h->tname) - unlink (h->tname); - xfree (h->tname); - xfree (h->lockname); - } - xfree(h); - - } -#endif -} - -#ifndef HAVE_DOSISH_SYSTEM - -static int -maybe_deadlock( DOTLOCK h ) -{ - DOTLOCK r; - - for( r=all_lockfiles; r; r = r->next ) { - if( r != h && r->locked ) - return 1; - } - return 0; -} - -/**************** - * Read the lock file and return the pid, returns -1 on error. - */ -static int -read_lockfile( const char *name ) -{ - int fd, pid; - char pidstr[16]; - - if( (fd = open(name, O_RDONLY)) == -1 ) { - int e = errno; - log_debug("error opening lockfile `%s': %s\n", name, strerror(errno) ); - errno = e; - return -1; - } - if( read(fd, pidstr, 10 ) != 10 ) { /* Read 10 digits w/o newline */ - log_debug("error reading lockfile `%s'", name ); - close(fd); - errno = 0; - return -1; - } - pidstr[10] = 0; /* terminate pid string */ - close(fd); - pid = atoi(pidstr); -#ifndef __riscos__ - if( !pid || pid == -1 ) { -#else /* __riscos__ */ - if( (!pid && riscos_getpid()) || pid == -1 ) { -#endif /* __riscos__ */ - log_error("invalid pid %d in lockfile `%s'", pid, name ); - errno = 0; - return -1; - } - return pid; -} -#endif /* !HAVE_DOSISH_SYSTEM */ - -/**************** - * Do a lock on H. A TIMEOUT of 0 returns immediately, - * -1 waits forever (hopefully not), other - * values are timeouts in milliseconds. - * Returns: 0 on success - */ -int -make_dotlock( DOTLOCK h, long timeout ) -{ -#if defined (HAVE_DOSISH_SYSTEM) - return 0; -#else - int pid; - const char *maybe_dead=""; - int backoff=0; - - if( h->disable ) { - return 0; - } - - if( h->locked ) { -#ifndef __riscos__ - log_debug("oops, `%s' is already locked\n", h->lockname ); -#endif /* !__riscos__ */ - return 0; - } - - for(;;) { -#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( !riscos_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->lockname)) == -1 ) { - if( errno != ENOENT ) { - log_info("cannot read lockfile\n"); - return -1; - } - log_info( "lockfile disappeared\n"); - continue; - } - else if( pid == getpid() ) { - log_info( "Oops: lock already held by us\n"); - h->locked = 1; - return 0; /* okay */ - } - else if( kill(pid, 0) && errno == ESRCH ) { -#ifndef __riscos__ - maybe_dead = " - probably dead"; -#if 0 /* we should not do this without checking the permissions */ - /* and the hostname */ - log_info( "removing stale lockfile (created by %d)", pid ); -#endif -#else /* __riscos__ */ - /* we are *pretty* sure that the other task is dead and therefore - we remove the other lock file */ - maybe_dead = " - probably dead - removing lock"; - unlink(h->lockname); -#endif /* __riscos__ */ - } - if( timeout == -1 ) { - struct timeval tv; - log_info( "waiting for lock (held by %d%s) %s...\n", - pid, maybe_dead, maybe_deadlock(h)? "(deadlock?) ":""); - - - /* 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; - } - /*not reached */ -#endif -} - - -/**************** - * release a lock - * Returns: 0 := success - */ -int -release_dotlock( DOTLOCK h ) -{ -#if defined (HAVE_DOSISH_SYSTEM) - return 0; -#else - int pid; - - /* 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; - } - - pid = read_lockfile( h->lockname ); - if( pid == -1 ) { - log_error( "release_dotlock: lockfile error\n"); - return -1; - } - if( pid != getpid() ) { - 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'", - h->lockname); - return -1; - } -#else /* __riscos__ */ - if( riscos_renamefile(h->lockname, h->tname) ) { - log_error( "release_dotlock: error renaming lockfile `%s' to `%s'", - h->lockname, h->tname); - return -1; - } -#endif /* __riscos__ */ - /* fixme: check that the link count is now 1 */ - h->locked = 0; - return 0; -#endif -} - -void -remove_lockfiles() -{ -#if !defined (HAVE_DOSISH_SYSTEM) - DOTLOCK h, h2; - - h = all_lockfiles; - all_lockfiles = NULL; - - while( h ) { - h2 = h->next; - destroy_dotlock (h); - h = h2; - } -#endif -} diff --git a/util/errors.c b/util/errors.c deleted file mode 100644 index 75498f80e..000000000 --- a/util/errors.c +++ /dev/null @@ -1,116 +0,0 @@ -/* errors.c - error strings - * Copyright (C) 1998, 1999, 2000, 2001 Free Software Foundation, Inc. - * - * This file is part of GnuPG. - * - * GnuPG is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * GnuPG is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, - * USA. - */ - -#include <config.h> -#include <stdio.h> -#include <stdlib.h> -#include <stdarg.h> - -#include "errors.h" -#include "i18n.h" - -#ifndef HAVE_STRERROR -char * -strerror( int n ) -{ - extern char *sys_errlist[]; - extern int sys_nerr; - static char buf[15]; - - if( n >= 0 && n < sys_nerr ) - return sys_errlist[n]; - strcpy( buf, "Unknown error" ); - return buf; -} -#endif /* !HAVE_STRERROR */ - -const char * -g10_errstr( int err ) -{ - static char buf[50]; - const char *p; - -#define X(n,s) case G10ERR_##n : p = s; break; - switch( err ) { - case -1: p = "eof"; break; - case 0: p = "okay"; break; - X(GENERAL, N_("general error")) - X(UNKNOWN_PACKET, N_("unknown packet type")) - X(UNKNOWN_VERSION,N_("unknown version")) - X(PUBKEY_ALGO ,N_("unknown pubkey algorithm")) - X(DIGEST_ALGO ,N_("unknown digest algorithm")) - X(BAD_PUBKEY ,N_("bad public key")) - X(BAD_SECKEY ,N_("bad secret key")) - X(BAD_SIGN ,N_("bad signature")) - X(CHECKSUM , N_("checksum error")) - X(BAD_PASS , N_("bad passphrase")) - X(NO_PUBKEY ,N_("public key not found")) - X(CIPHER_ALGO ,N_("unknown cipher algorithm")) - X(KEYRING_OPEN ,N_("can't open the keyring")) - X(INVALID_PACKET ,N_("invalid packet")) - X(INVALID_ARMOR ,N_("invalid armor")) - X(NO_USER_ID ,N_("no such user id")) - X(NO_SECKEY ,N_("secret key not available")) - X(WRONG_SECKEY ,N_("wrong secret key used")) - X(UNSUPPORTED ,N_("not supported")) - X(BAD_KEY ,N_("bad key")) - X(READ_FILE ,N_("file read error")) - X(WRITE_FILE ,N_("file write error")) - X(COMPR_ALGO ,N_("unknown compress algorithm")) - X(OPEN_FILE ,N_("file open error")) - X(CREATE_FILE ,N_("file create error")) - X(PASSPHRASE ,N_("invalid passphrase")) - X(NI_PUBKEY ,N_("unimplemented pubkey algorithm")) - X(NI_CIPHER ,N_("unimplemented cipher algorithm")) - X(SIG_CLASS ,N_("unknown signature class")) - X(TRUSTDB ,N_("trust database error")) - X(BAD_MPI ,N_("bad MPI")) - X(RESOURCE_LIMIT ,N_("resource limit")) - X(INV_KEYRING ,N_("invalid keyring")) - X(BAD_CERT ,N_("bad certificate")) - X(INV_USER_ID ,N_("malformed user id")) - X(CLOSE_FILE ,N_("file close error")) - X(RENAME_FILE ,N_("file rename error")) - X(DELETE_FILE ,N_("file delete error")) - X(UNEXPECTED ,N_("unexpected data")) - X(TIME_CONFLICT ,N_("timestamp conflict")) - X(WR_PUBKEY_ALGO ,N_("unusable pubkey algorithm")) - X(FILE_EXISTS ,N_("file exists")) - X(WEAK_KEY ,N_("weak key")) - X(INV_ARG ,N_("invalid argument")) - X(BAD_URI ,N_("bad URI")) - X(INVALID_URI ,N_("unsupported URI")) - X(NETWORK ,N_("network error")) - X(SELFTEST_FAILED,"selftest failed") - X(NOT_ENCRYPTED ,N_("not encrypted")) - X(NOT_PROCESSED ,N_("not processed")) - /* the key cannot be used for a specific usage */ - X(UNU_PUBKEY ,N_("unusable public key")) - X(UNU_SECKEY ,N_("unusable secret key")) - X(KEYSERVER ,N_("keyserver error")) - X(CANCELED ,N_("canceled")) - X(NO_CARD ,N_("no card")) - X(NO_DATA ,N_("no data")) - default: p = buf; sprintf(buf, "g10err=%d", err); break; - } -#undef X - return _(p); -} diff --git a/util/fileutil.c b/util/fileutil.c deleted file mode 100644 index 5834e3d89..000000000 --- a/util/fileutil.c +++ /dev/null @@ -1,297 +0,0 @@ -/* fileutil.c - file utilities - * Copyright (C) 1998, 2003, 2005 Free Software Foundation, Inc. - * - * This file is part of GnuPG. - * - * GnuPG is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * GnuPG is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, - * USA. - */ - -#include <config.h> -#include <stdio.h> -#include <stdlib.h> -#include <stdarg.h> -#include <string.h> -#include <assert.h> -#include <unistd.h> -#include <sys/types.h> -#ifdef HAVE_PWD_H -#include <pwd.h> -#endif -#include "util.h" -#include "memory.h" -#include "ttyio.h" - - -/*************** - * Extract from a given path the filename component. - * - */ -char * -make_basename(const char *filepath, const char *inputpath) -{ -#ifdef __riscos__ - return riscos_make_basename(filepath, inputpath); -#endif - - char *p; - - if ( !(p=strrchr(filepath, DIRSEP_C)) ) -#ifdef HAVE_DRIVE_LETTERS - if ( !(p=strrchr(filepath, '\\')) ) - if ( !(p=strrchr(filepath, ':')) ) -#endif - { - return xstrdup(filepath); - } - - return xstrdup(p+1); -} - - - -/*************** - * Extract from a given filename the path prepended to it. - * If their isn't a path prepended to the filename, a dot - * is returned ('.'). - * - */ -char * -make_dirname(const char *filepath) -{ - char *dirname; - int dirname_length; - char *p; - - if ( !(p=strrchr(filepath, DIRSEP_C)) ) -#ifdef HAVE_DRIVE_LETTERS - if ( !(p=strrchr(filepath, '\\')) ) - if ( !(p=strrchr(filepath, ':')) ) -#endif - { - return xstrdup(EXTSEP_S); - } - - dirname_length = p-filepath; - dirname = xmalloc(dirname_length+1); - strncpy(dirname, filepath, dirname_length); - dirname[dirname_length] = 0; - - return dirname; -} - -/* Expand tildes. Handles both the ~/foo and ~username/foo cases. - Returns what the tilde expands to. *name is advanced to be past - the tilde expansion. */ -static char * -untilde(const char **name) -{ - char *home=NULL; - - assert((*name)[0]=='~'); - - if((*name)[1]==DIRSEP_C || (*name)[1]=='\0') - { - /* This is the "~/foo" or "~" case. */ - char *tmp=getenv("HOME"); - if(tmp) - home=xstrdup(tmp); - -#ifdef HAVE_GETPWUID - if(!home) - { - struct passwd *pwd; - - pwd=getpwuid(getuid()); - if(pwd) - home=xstrdup(pwd->pw_dir); - } -#endif - if(home) - (*name)++; - } -#ifdef HAVE_GETPWNAM - else - { - /* This is the "~username" case. */ - char *user,*sep; - struct passwd *pwd; - - user=xstrdup((*name)+1); - - sep=strchr(user,DIRSEP_C); - if(sep) - *sep='\0'; - - pwd=getpwnam(user); - if(pwd) - { - home=xstrdup(pwd->pw_dir); - (*name)+=1+strlen(user); - } - - xfree(user); - } -#endif - - return home; -} - -/* - Construct a filename from the NULL terminated list of parts. Tilde - expansion is done here. Note that FIRST_PART must never be NULL and - that this function is guaranteed to return an allocated string. */ -char * -make_filename( const char *first_part, ... ) -{ - va_list arg_ptr ; - size_t n; - const char *s; - char *name, *p, *home=NULL; - - va_start( arg_ptr, first_part ) ; - n = strlen(first_part)+1; - while( (s=va_arg(arg_ptr, const char *)) ) - n += strlen(s) + 1; - va_end(arg_ptr); - -#ifndef __riscos__ - if(*first_part=='~') - { - home=untilde(&first_part); - if(home) - n+=strlen(home); - } -#endif - name = xmalloc(n); - p = home ? stpcpy(stpcpy(name,home), first_part) - : stpcpy(name, first_part); - va_start( arg_ptr, first_part ) ; - while( (s=va_arg(arg_ptr, const char *)) ) - p = stpcpy(stpcpy(p, DIRSEP_S), s); - va_end(arg_ptr); - xfree(home); - -#ifndef __riscos__ - return name; -#else /* __riscos__ */ - p = riscos_gstrans(name); - xfree(name); - return p; -#endif /* __riscos__ */ -} - - -int -compare_filenames( const char *a, const char *b ) -{ - /* ? check whether this is an absolute filename and - * resolve symlinks? - */ -#ifndef __riscos__ -#ifdef HAVE_DRIVE_LETTERS - return ascii_strcasecmp(a,b); -#else - return strcmp(a,b); -#endif -#else /* __riscos__ */ - int c = 0; - char *abuf, *bbuf; - - abuf = riscos_gstrans(a); - bbuf = riscos_gstrans(b); - - c = ascii_strcasecmp (abuf, bbuf); - - xfree(abuf); - xfree(bbuf); - - return c; -#endif /* __riscos__ */ -} - - -/**************** - * A simple function to decide whether the filename is stdout - * or a real filename. - */ -const char * -print_fname_stdout( const char *s ) -{ - if( !s || (*s == '-' && !s[1]) ) - return "[stdout]"; - return s; -} - - -const char * -print_fname_stdin( const char *s ) -{ - if( !s || (*s == '-' && !s[1]) ) - return "[stdin]"; - return s; -} - -/**************** - * Check if the file is compressed. - **/ -int -is_file_compressed( const char *s, int *ret_rc ) -{ - IOBUF a; - byte buf[4]; - int i, rc = 0; - int overflow; - - struct magic_compress_s { - size_t len; - byte magic[4]; - } magic[] = { - { 3, { 0x42, 0x5a, 0x68, 0x00 } }, /* bzip2 */ - { 3, { 0x1f, 0x8b, 0x08, 0x00 } }, /* gzip */ - { 4, { 0x50, 0x4b, 0x03, 0x04 } }, /* (pk)zip */ - }; - - if ( iobuf_is_pipe_filename (s) || !ret_rc ) - return 0; /* We can't check stdin or no file was given */ - - a = iobuf_open( s ); - if ( a == NULL ) { - *ret_rc = G10ERR_OPEN_FILE; - return 0; - } - - if ( iobuf_get_filelength( a, &overflow ) < 4 && !overflow) { - *ret_rc = 0; - goto leave; - } - - if ( iobuf_read( a, buf, 4 ) == -1 ) { - *ret_rc = G10ERR_READ_FILE; - goto leave; - } - - for ( i = 0; i < DIM( magic ); i++ ) { - if ( !memcmp( buf, magic[i].magic, magic[i].len ) ) { - *ret_rc = 0; - rc = 1; - break; - } - } - -leave: - iobuf_close( a ); - return rc; -} diff --git a/util/http.c b/util/http.c deleted file mode 100644 index 41000024f..000000000 --- a/util/http.c +++ /dev/null @@ -1,1076 +0,0 @@ -/* http.c - HTTP protocol handler - * Copyright (C) 1999, 2001, 2002, 2003, 2004, - * 2005 Free Software Foundation, Inc. - * - * This file is part of GnuPG. - * - * GnuPG is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * GnuPG is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, - * USA. - */ - -#include <config.h> -#include <stdio.h> -#include <stdlib.h> -#include <stdarg.h> -#include <string.h> -#include <ctype.h> -#include <errno.h> - -#ifdef _WIN32 -#include <windows.h> -#else -#include <unistd.h> -#include <sys/types.h> -#include <sys/socket.h> -#include <sys/time.h> -#include <time.h> -#include <netinet/in.h> -#include <arpa/inet.h> -#include <netdb.h> -#endif - -#include "util.h" -#include "iobuf.h" -#include "i18n.h" -#include "http.h" -#include "srv.h" - -#ifdef _WIN32 -#define sock_close(a) closesocket(a) -#else -#define sock_close(a) close(a) -#endif - -#define MAX_LINELEN 20000 /* max. length of a HTTP line */ -#define VALID_URI_CHARS "abcdefghijklmnopqrstuvwxyz" \ - "ABCDEFGHIJKLMNOPQRSTUVWXYZ" \ - "01234567890@" \ - "!\"#$%&'()*+,-./:;<=>?[\\]^_{|}~" - -#ifndef EAGAIN -#define EAGAIN EWOULDBLOCK -#endif - -static int parse_uri( PARSED_URI *ret_uri, const char *uri ); -static void release_parsed_uri( PARSED_URI uri ); -static int do_parse_uri( PARSED_URI uri, int only_local_part ); -static int remove_escapes( byte *string ); -static int insert_escapes( byte *buffer, const byte *string, - const byte *special ); -static URI_TUPLE parse_tuple( byte *string ); -static int send_request( HTTP_HD hd, const char *auth, const char *proxy ); -static byte *build_rel_path( PARSED_URI uri ); -static int parse_response( HTTP_HD hd ); - -static int connect_server( const char *server, ushort port, unsigned int flags, - const char *srvtag ); -static int write_server( int sock, const char *data, size_t length ); - -#ifdef _WIN32 -static void -deinit_sockets (void) -{ - WSACleanup(); -} - -static void -init_sockets (void) -{ - static int initialized; - static WSADATA wsdata; - - if (initialized) - return; - - if( WSAStartup( 0x0101, &wsdata ) ) { - log_error ("error initializing socket library: ec=%d\n", - (int)WSAGetLastError () ); - return; - } - if( wsdata.wVersion < 0x0001 ) { - log_error ("socket library version is %x.%x - but 1.1 needed\n", - LOBYTE(wsdata.wVersion), HIBYTE(wsdata.wVersion)); - WSACleanup(); - return; - } - atexit ( deinit_sockets ); - initialized = 1; -} -#endif /*_WIN32*/ - -static byte bintoasc[] = "ABCDEFGHIJKLMNOPQRSTUVWXYZ" - "abcdefghijklmnopqrstuvwxyz" - "0123456789+/"; - -/**************** - * create a radix64 encoded string. - */ - -/* TODO: This is a duplicate of code in g10/armor.c modified to do the - "=" padding. Better to use a single copy in strgutil.c ? */ -static char * -make_radix64_string( const byte *data, size_t len ) -{ - char *buffer, *p; - - buffer = p = xmalloc( (len+2)/3*4 + 1 ); - for( ; len >= 3 ; len -= 3, data += 3 ) { - *p++ = bintoasc[(data[0] >> 2) & 077]; - *p++ = bintoasc[(((data[0] <<4)&060)|((data[1] >> 4)&017))&077]; - *p++ = bintoasc[(((data[1]<<2)&074)|((data[2]>>6)&03))&077]; - *p++ = bintoasc[data[2]&077]; - } - if( len == 2 ) { - *p++ = bintoasc[(data[0] >> 2) & 077]; - *p++ = bintoasc[(((data[0] <<4)&060)|((data[1] >> 4)&017))&077]; - *p++ = bintoasc[((data[1]<<2)&074)]; - *p++ = '='; - } - else if( len == 1 ) { - *p++ = bintoasc[(data[0] >> 2) & 077]; - *p++ = bintoasc[(data[0] <<4)&060]; - *p++ = '='; - *p++ = '='; - } - *p = 0; - return buffer; -} - -int -http_open( HTTP_HD hd, HTTP_REQ_TYPE reqtype, const char *url, - char *auth, unsigned int flags, const char *proxy ) -{ - int rc; - - if( !(reqtype == HTTP_REQ_GET || reqtype == HTTP_REQ_POST) ) - return G10ERR_INV_ARG; - - /* initialize the handle */ - memset( hd, 0, sizeof *hd ); - hd->sock = -1; - hd->initialized = 1; - hd->req_type = reqtype; - hd->flags = flags; - - rc = parse_uri( &hd->uri, url ); - if( !rc ) { - rc = send_request( hd, auth, proxy ); - if( !rc ) { - hd->fp_write = iobuf_sockopen( hd->sock , "w" ); - if( hd->fp_write ) - return 0; - rc = G10ERR_GENERAL; - } - } - - if( !hd->fp_read && !hd->fp_write && hd->sock != -1 ) - sock_close( hd->sock ); - iobuf_close( hd->fp_read ); - iobuf_close( hd->fp_write); - release_parsed_uri( hd->uri ); - hd->initialized = 0; - - return rc; -} - - -void -http_start_data( HTTP_HD hd ) -{ - iobuf_flush ( hd->fp_write ); - if( !hd->in_data ) { - write_server (hd->sock, "\r\n", 2); - hd->in_data = 1; - } -} - - -int -http_wait_response( HTTP_HD hd, unsigned int *ret_status ) -{ - int rc; - - http_start_data( hd ); /* make sure that we are in the data */ - -#if 0 - hd->sock = dup( hd->sock ); - if( hd->sock == -1 ) - return G10ERR_GENERAL; -#endif - iobuf_ioctl (hd->fp_write, 1, 1, NULL); /* keep the socket open */ - iobuf_close (hd->fp_write); - hd->fp_write = NULL; - if ( !(hd->flags & HTTP_FLAG_NO_SHUTDOWN) ) - shutdown( hd->sock, 1 ); - hd->in_data = 0; - - hd->fp_read = iobuf_sockopen( hd->sock , "r" ); - if( !hd->fp_read ) - return G10ERR_GENERAL; - - rc = parse_response( hd ); - if( !rc && ret_status ) - *ret_status = hd->status_code; - - return rc; -} - - -int -http_open_document( HTTP_HD hd, const char *document, char *auth, - unsigned int flags, const char *proxy ) -{ - int rc; - - rc = http_open(hd, HTTP_REQ_GET, document, auth, flags, proxy ); - if( rc ) - return rc; - - rc = http_wait_response( hd, NULL ); - if( rc ) - http_close( hd ); - - return rc; -} - - -void -http_close( HTTP_HD hd ) -{ - if( !hd || !hd->initialized ) - return; - if( !hd->fp_read && !hd->fp_write && hd->sock != -1 ) - sock_close( hd->sock ); - iobuf_close( hd->fp_read ); - iobuf_close( hd->fp_write ); - release_parsed_uri( hd->uri ); - xfree( hd->buffer ); - hd->initialized = 0; -} - - - -/**************** - * Parse an URI and put the result into the newly allocated ret_uri. - * The caller must always use release_parsed_uri to releases the - * resources (even on an error). - */ -static int -parse_uri( PARSED_URI *ret_uri, const char *uri ) -{ - *ret_uri = xmalloc_clear( sizeof(**ret_uri) + strlen(uri) ); - strcpy( (*ret_uri)->buffer, uri ); - return do_parse_uri( *ret_uri, 0 ); -} - -static void -release_parsed_uri( PARSED_URI uri ) -{ - if( uri ) - { - URI_TUPLE r, r2; - - for( r = uri->query; r; r = r2 ) { - r2 = r->next; - xfree( r ); - } - xfree( uri ); - } -} - -static int -do_parse_uri( PARSED_URI uri, int only_local_part ) -{ - URI_TUPLE *tail; - char *p, *p2, *p3; - int n; - - p = uri->buffer; - n = strlen( uri->buffer ); - /* initialize all fields to an empty string or an empty list */ - uri->scheme = uri->host = uri->path = p + n; - uri->port = 0; - uri->params = uri->query = NULL; - - /* a quick validity check */ - if( strspn( p, VALID_URI_CHARS) != n ) - return G10ERR_BAD_URI; /* invalid characters found */ - - if( !only_local_part ) { - /* find the scheme */ - if( !(p2 = strchr( p, ':' ) ) || p2 == p ) - return G10ERR_BAD_URI; /* No scheme */ - *p2++ = 0; - strlwr( p ); - uri->scheme = p; - if(strcmp(uri->scheme,"http")==0) - uri->port = 80; - else if(strcmp(uri->scheme,"hkp")==0) - uri->port = 11371; - else - return G10ERR_INVALID_URI; /* Unsupported scheme */ - - p = p2; - - /* find the hostname */ - if( *p != '/' ) - return G10ERR_INVALID_URI; /* does not start with a slash */ - - p++; - if( *p == '/' ) { /* there seems to be a hostname */ - p++; - if( (p2 = strchr(p, '/')) ) - *p2++ = 0; - - /* Check for username/password encoding */ - if((p3=strchr(p,'@'))) - { - uri->auth=p; - *p3++='\0'; - p=p3; - } - - strlwr( p ); - uri->host = p; - if( (p3=strchr( p, ':' )) ) { - *p3++ = 0; - uri->port = atoi( p3 ); - } - - uri->host = p; - if( (n = remove_escapes( uri->host )) < 0 ) - return G10ERR_BAD_URI; - if( n != strlen( p ) ) - return G10ERR_BAD_URI; /* hostname with a Nul in it */ - p = p2 ? p2 : NULL; - } - } /* end global URI part */ - - /* parse the pathname part */ - if( !p || !*p ) /* we don't have a path */ - return 0; /* and this is okay */ - - /* todo: here we have to check params */ - - /* do we have a query part */ - if( (p2 = strchr( p, '?' )) ) - *p2++ = 0; - - uri->path = p; - if( (n = remove_escapes( p )) < 0 ) - return G10ERR_BAD_URI; - if( n != strlen( p ) ) - return G10ERR_BAD_URI; /* path with a Nul in it */ - p = p2 ? p2 : NULL; - - if( !p || !*p ) /* we don't have a query string */ - return 0; /* okay */ - - /* now parse the query string */ - tail = &uri->query; - for(;;) { - URI_TUPLE elem; - - if( (p2 = strchr( p, '&' )) ) - *p2++ = 0; - if( !(elem = parse_tuple( p )) ) - return G10ERR_BAD_URI; - *tail = elem; - tail = &elem->next; - - if( !p2 ) - break; /* ready */ - p = p2; - } - - return 0; -} - - - -/**************** - * Remove all %xx escapes; this is done inplace. - * Returns: new length of the string. - */ -static int -remove_escapes( byte *string ) -{ - int n = 0; - byte *p, *s; - - for(p=s=string; *s ; s++ ) { - if( *s == '%' ) { - if( s[1] && s[2] && isxdigit(s[1]) && isxdigit(s[2]) ) { - s++; - *p = *s >= '0' && *s <= '9' ? *s - '0' : - *s >= 'A' && *s <= 'F' ? *s - 'A' + 10 : *s - 'a' + 10 ; - *p <<= 4; - s++; - *p |= *s >= '0' && *s <= '9' ? *s - '0' : - *s >= 'A' && *s <= 'F' ? *s - 'A' + 10 : *s - 'a' + 10 ; - p++; - n++; - } - else { - *p++ = *s++; - if( *s ) - *p++ = *s++; - if( *s ) - *p++ = *s++; - if( *s ) - *p = 0; - return -1; /* bad URI */ - } - } - else - { - *p++ = *s; - n++; - } - } - *p = 0; /* always keep a string terminator */ - return n; -} - - -static int -insert_escapes( byte *buffer, const byte *string, const byte *special ) -{ - int n = 0; - - for( ; *string; string++ ) { - if( strchr( VALID_URI_CHARS, *string ) - && !strchr( special, *string ) ) { - if( buffer ) - *buffer++ = *string; - n++; - } - else { - if( buffer ) { - sprintf( buffer, "%%%02X", *string ); - buffer += 3; - } - n += 3; - } - } - return n; -} - - -static URI_TUPLE -parse_tuple( byte *string ) -{ - byte *p = string; - byte *p2; - int n; - URI_TUPLE tuple; - - if( (p2 = strchr( p, '=' )) ) - *p2++ = 0; - if( (n = remove_escapes( p )) < 0 ) - return NULL; /* bad URI */ - if( n != strlen( p ) ) - return NULL; /* name with a Nul in it */ - tuple = xmalloc_clear( sizeof *tuple ); - tuple->name = p; - if( !p2 ) { - /* we have only the name, so we assume an empty value string */ - tuple->value = p + strlen(p); - tuple->valuelen = 0; - } - else { /* name and value */ - if( (n = remove_escapes( p2 )) < 0 ) { - xfree( tuple ); - return NULL; /* bad URI */ - } - tuple->value = p2; - tuple->valuelen = n; - } - return tuple; -} - - -/**************** - * Send a HTTP request to the server - * Returns 0 if the request was successful - */ -static int -send_request( HTTP_HD hd, const char *auth, const char *proxy ) -{ - const byte *server; - byte *request, *p; - ushort port; - int rc; - char *proxy_authstr=NULL,*authstr=NULL; - - server = *hd->uri->host? hd->uri->host : "localhost"; - port = hd->uri->port? hd->uri->port : 80; - - if(proxy && *proxy) - { - PARSED_URI uri; - - rc = parse_uri( &uri, proxy ); - if (rc) - { - log_error("invalid HTTP proxy (%s): %s\n",proxy,g10_errstr(rc)); - release_parsed_uri( uri ); - return G10ERR_NETWORK; - } - hd->sock = connect_server( *uri->host? uri->host : "localhost", - uri->port? uri->port : 80, 0, NULL ); - if(uri->auth) - { - char *x; - remove_escapes(uri->auth); - x=make_radix64_string(uri->auth,strlen(uri->auth)); - proxy_authstr=xmalloc(52+strlen(x)); - sprintf(proxy_authstr,"Proxy-Authorization: Basic %s\r\n",x); - xfree(x); - } - - release_parsed_uri( uri ); - } - else - hd->sock = connect_server( server, port, hd->flags, hd->uri->scheme ); - - if(auth || hd->uri->auth) - { - char *x,*tempauth=NULL; - - if(auth) - { - tempauth=xstrdup(auth); - remove_escapes(tempauth); - } - else if(hd->uri->auth) - remove_escapes(hd->uri->auth); - - x=make_radix64_string(tempauth?tempauth:hd->uri->auth, - strlen(tempauth?tempauth:hd->uri->auth)); - authstr=xmalloc(52+strlen(x)); - sprintf(authstr,"Authorization: Basic %s\r\n",x); - xfree(x); - xfree(tempauth); - } - - if( hd->sock == -1 ) - return G10ERR_NETWORK; - - p = build_rel_path( hd->uri ); - - request=xmalloc(strlen(server)*2 + strlen(p) - + (authstr?strlen(authstr):0) - + (proxy_authstr?strlen(proxy_authstr):0) + 65); - if( proxy && *proxy ) - sprintf( request, "%s http://%s:%hu%s%s HTTP/1.0\r\n%s%s", - hd->req_type == HTTP_REQ_GET ? "GET" : - hd->req_type == HTTP_REQ_HEAD? "HEAD": - hd->req_type == HTTP_REQ_POST? "POST": "OOPS", - server, port, *p == '/'? "":"/", p, - authstr?authstr:"",proxy_authstr?proxy_authstr:"" ); - else - { - char portstr[15]; - - if(port!=80) - sprintf(portstr,":%u",port); - - sprintf( request, "%s %s%s HTTP/1.0\r\nHost: %s%s\r\n%s", - hd->req_type == HTTP_REQ_GET ? "GET" : - hd->req_type == HTTP_REQ_HEAD? "HEAD": - hd->req_type == HTTP_REQ_POST? "POST": "OOPS", - *p == '/'? "":"/", p, server, (port!=80)?portstr:"", - authstr?authstr:""); - } - - xfree(p); - - rc = write_server( hd->sock, request, strlen(request) ); - xfree( request ); - xfree(proxy_authstr); - xfree(authstr); - - return rc; -} - - -/**************** - * Build the relative path from the parsed URI. - * Minimal implementation. - */ -static byte* -build_rel_path( PARSED_URI uri ) -{ - URI_TUPLE r; - byte *rel_path, *p; - int n; - - /* count the needed space */ - n = insert_escapes( NULL, uri->path, "%;?&" ); - /* todo: build params */ - for( r=uri->query; r; r = r->next ) { - n++; /* '?'/'&' */ - n += insert_escapes( NULL, r->name, "%;?&=" ); - n++; /* '='*/ - n += insert_escapes( NULL, r->value, "%;?&=" ); - } - n++; - - /* now allocate and copy */ - p = rel_path = xmalloc( n ); - n = insert_escapes( p, uri->path, "%;?&" ); - p += n; - /* todo: add params */ - for( r=uri->query; r; r = r->next ) { - *p++ = r == uri->query? '?':'&'; - n = insert_escapes( p, r->name, "%;?&=" ); - p += n; - *p++ = '='; - /* todo: use valuelen */ - n = insert_escapes( p, r->value, "%;?&=" ); - p += n; - } - *p = 0; - return rel_path; -} - - - -/*********************** - * Parse the response from a server. - * Returns: errorcode and sets some fileds in the handle - */ -static int -parse_response( HTTP_HD hd ) -{ - byte *line, *p, *p2; - unsigned maxlen, len; - - /* Wait for the status line */ - do { - maxlen = MAX_LINELEN; - len = iobuf_read_line( hd->fp_read, &hd->buffer, - &hd->buffer_size, &maxlen ); - line = hd->buffer; - if( !maxlen ) - return -1; /* line has been truncated */ - if( !len ) - return -1; /* eof */ - } while( !*line ); - - if( (p = strchr( line, '/')) ) - *p++ = 0; - if( !p || strcmp( line, "HTTP" ) ) - return 0; /* assume http 0.9 */ - - if( (p2 = strpbrk( p, " \t" ) ) ) { - *p2++ = 0; - p2 += strspn( p2, " \t" ); - } - if( !p2 ) - return 0; /* assume http 0.9 */ - p = p2; - /* todo: add HTTP version number check here */ - if( (p2 = strpbrk( p, " \t" ) ) ) - *p2++ = 0; - if( !isdigit(p[0]) || !isdigit(p[1]) || !isdigit(p[2]) || p[3] ) { - /* malformed HTTP statuscode - assume HTTP 0.9 */ - hd->is_http_0_9 = 1; - hd->status_code = 200; - return 0; - } - hd->status_code = atoi( p ); - - /* skip all the header lines and wait for the empty line */ - do { - maxlen = MAX_LINELEN; - len = iobuf_read_line( hd->fp_read, &hd->buffer, - &hd->buffer_size, &maxlen ); - line = hd->buffer; - /* we ignore truncated lines */ - if( !len ) - return -1; /* eof */ - /* time lineendings */ - if( (*line == '\r' && line[1] == '\n') || *line == '\n' ) - *line = 0; - } while( len && *line ); - - return 0; -} - -#ifdef TEST -static int -start_server() -{ - struct sockaddr_in mya; - struct sockaddr_in peer; - int fd, client; - fd_set rfds; - int addrlen; - int i; - - if( (fd=socket(AF_INET,SOCK_STREAM, 0)) == -1 ) { - log_error("socket() failed: %s\n", strerror(errno)); - return -1; - } - i = 1; - if( setsockopt( fd, SOL_SOCKET, SO_REUSEADDR, (byte*)&i, sizeof(i) ) ) - log_info("setsockopt(SO_REUSEADDR) failed: %s\n", strerror(errno) ); - - mya.sin_family=AF_INET; - memset(&mya.sin_addr, 0, sizeof(mya.sin_addr)); - mya.sin_port=htons(11371); - - if( bind( fd, (struct sockaddr *)&mya, sizeof(mya)) ) { - log_error("bind to port 11371 failed: %s\n", strerror(errno) ); - sock_close( fd ); - return -1; - } - - if( listen( fd, 5 ) ) { - log_error("listen failed: %s\n", strerror(errno) ); - sock_close( fd ); - return -1; - } - - for(;;) { - FD_ZERO(&rfds); - FD_SET( fd, &rfds ); - - if( select( fd+1, &rfds, NULL, NULL, NULL) <= 0 ) - continue; /* ignore any errors */ - - if( !FD_ISSET( fd, &rfds ) ) - continue; - - addrlen = sizeof peer; - client = accept( fd, (struct sockaddr *)&peer, &addrlen); - if( client == -1 ) - continue; /* oops */ - - log_info("connect from %s\n", inet_ntoa( peer.sin_addr ) ); - - fflush(stdout); - fflush(stderr); - if( !fork() ) { - int c; - FILE *fp; - - fp = fdopen( client , "r" ); - while( (c=getc(fp)) != EOF ) - putchar(c); - fclose(fp); - exit(0); - } - sock_close( client ); - } - - - return 0; -} -#endif - - -static int -connect_server( const char *server, ushort port, unsigned int flags, - const char *srvtag ) -{ - int sock=-1,srv,srvcount=0,connected=0,hostfound=0; - struct srventry *srvlist=NULL; - -#ifdef _WIN32 - unsigned long inaddr; - - init_sockets(); - /* Win32 gethostbyname doesn't handle IP addresses internally, so we - try inet_addr first on that platform only. */ - if((inaddr=inet_addr(server))!=INADDR_NONE) - { - struct sockaddr_in addr; - - memset(&addr,0,sizeof(addr)); - - if((sock=socket(AF_INET,SOCK_STREAM,0))==INVALID_SOCKET) - { - log_error("error creating socket: ec=%d\n",(int)WSAGetLastError()); - return -1; - } - - addr.sin_family=AF_INET; - addr.sin_port=htons(port); - memcpy(&addr.sin_addr,&inaddr,sizeof(inaddr)); - - if(connect(sock,(struct sockaddr *)&addr,sizeof(addr))==0) - return sock; - else - { - sock_close(sock); - return -1; - } - } -#endif - -#ifdef USE_DNS_SRV - /* Do the SRV thing */ - if(flags&HTTP_FLAG_TRY_SRV && srvtag) - { - /* We're using SRV, so append the tags */ - if(1+strlen(srvtag)+6+strlen(server)+1<=MAXDNAME) - { - char srvname[MAXDNAME]; - - strcpy(srvname,"_"); - strcat(srvname,srvtag); - strcat(srvname,"._tcp."); - strcat(srvname,server); - srvcount=getsrv(srvname,&srvlist); - } - } -#endif - - if(srvlist==NULL) - { - /* Either we're not using SRV, or the SRV lookup failed. Make - up a fake SRV record. */ - srvlist=xmalloc_clear(sizeof(struct srventry)); - srvlist->port=port; - strncpy(srvlist->target,server,MAXDNAME); - srvlist->target[MAXDNAME-1]='\0'; - srvcount=1; - } - -#ifdef HAVE_GETADDRINFO - - for(srv=0;srv<srvcount;srv++) - { - struct addrinfo hints,*res,*ai; - char portstr[6]; - - sprintf(portstr,"%u",srvlist[srv].port); - memset(&hints,0,sizeof(hints)); - hints.ai_socktype=SOCK_STREAM; - if(getaddrinfo(srvlist[srv].target,portstr,&hints,&res)==0) - hostfound=1; - else - continue; - - for(ai=res;ai;ai=ai->ai_next) - { - if((sock=socket(ai->ai_family,ai->ai_socktype,ai->ai_protocol))==-1) - { - log_error("error creating socket: %s\n",strerror(errno)); - freeaddrinfo(res); - return -1; - } - - if(connect(sock,ai->ai_addr,ai->ai_addrlen)==0) - { - connected=1; - break; - } - - sock_close(sock); - } - - freeaddrinfo(res); - - if(ai) - break; - } - -#else /* !HAVE_GETADDRINFO */ - - for(srv=0;srv<srvcount;srv++) - { - int i=0; - struct hostent *host=NULL; - struct sockaddr_in addr; - - memset(&addr,0,sizeof(addr)); - - if((host=gethostbyname(srvlist[srv].target))==NULL) - continue; - - hostfound=1; - - if((sock=socket(host->h_addrtype,SOCK_STREAM,0))==-1) - { - log_error("error creating socket: %s\n",strerror(errno)); - return -1; - } - - addr.sin_family=host->h_addrtype; - if(addr.sin_family!=AF_INET) - { - log_error("%s: unknown address family\n",srvlist[srv].target); - return -1; - } - - addr.sin_port=htons(srvlist[srv].port); - - /* Try all A records until one responds. */ - while(host->h_addr_list[i]) - { - if(host->h_length!=4) - { - log_error("%s: illegal address length\n",srvlist[srv].target); - return -1; - } - - memcpy(&addr.sin_addr,host->h_addr_list[i],host->h_length); - - if(connect(sock,(struct sockaddr *)&addr,sizeof(addr))==0) - { - connected=1; - break; - } - - i++; - } - - if(host->h_addr_list[i]) - break; - - sock_close(sock); - } -#endif /* !HAVE_GETADDRINFO */ - - xfree(srvlist); - - if(!connected) - { - int err=errno; -#ifdef _WIN32 - if(hostfound) - log_error("%s: Unable to connect: ec=%d\n",server,(int)WSAGetLastError()); - else - log_error("%s: Host not found: ec=%d\n",server,(int)WSAGetLastError()); -#else - if(hostfound) - log_error("%s: %s\n",server,strerror(err)); - else - log_error("%s: Host not found\n",server); -#endif - if(sock!=-1) - sock_close(sock); - errno=err; - return -1; - } - - return sock; -} - - -static int -write_server( int sock, const char *data, size_t length ) -{ - int nleft; - - nleft = length; - while( nleft > 0 ) { -#ifdef _WIN32 - int nwritten; - - nwritten = send (sock, data, nleft, 0); - if ( nwritten == SOCKET_ERROR ) { - log_info ("write failed: ec=%d\n", (int)WSAGetLastError ()); - return G10ERR_NETWORK; - } -#else - int nwritten = write( sock, data, nleft ); - if( nwritten == -1 ) { - if( errno == EINTR ) - continue; - if( errno == EAGAIN ) { - struct timeval tv; - - tv.tv_sec = 0; - tv.tv_usec = 50000; - select(0, NULL, NULL, NULL, &tv); - continue; - } - log_info("write failed: %s\n", strerror(errno)); - return G10ERR_NETWORK; - } -#endif - nleft -=nwritten; - data += nwritten; - } - - return 0; -} - -/**** Test code ****/ -#ifdef TEST - -int -main(int argc, char **argv) -{ - int rc; - PARSED_URI uri; - URI_TUPLE r; - struct http_context hd; - int c; - - log_set_name("http-test"); - if( argc == 1 ) { - start_server(); - return 0; - } - - if( argc != 2 ) { - fprintf(stderr,"usage: http-test uri\n"); - return 1; - } - argc--; argv++; - - rc = parse_uri( &uri, *argv ); - if( rc ) { - log_error("`%s': %s\n", *argv, g10_errstr(rc)); - release_parsed_uri( uri ); - return 1; - } - - printf("Scheme: %s\n", uri->scheme ); - printf("Host : %s\n", uri->host ); - printf("Port : %u\n", uri->port ); - printf("Path : %s\n", uri->path ); - for( r=uri->params; r; r = r->next ) { - printf("Params: %s=%s", r->name, r->value ); - if( strlen( r->value ) != r->valuelen ) - printf(" [real length=%d]", (int)r->valuelen ); - putchar('\n'); - } - for( r=uri->query; r; r = r->next ) { - printf("Query : %s=%s", r->name, r->value ); - if( strlen( r->value ) != r->valuelen ) - printf(" [real length=%d]", (int)r->valuelen ); - putchar('\n'); - } - release_parsed_uri( uri ); uri = NULL; - - rc = http_open_document( &hd, *argv, 0, NULL ); - if( rc ) { - log_error("can't get `%s': %s\n", *argv, g10_errstr(rc)); - return 1; - } - log_info("open_http_document succeeded; status=%u\n", hd.status_code ); - while( (c=iobuf_get( hd.fp_read)) != -1 ) - putchar(c); - http_close( &hd ); - return 0; -} -#endif /*TEST*/ diff --git a/util/iobuf.c b/util/iobuf.c deleted file mode 100644 index f6e817c42..000000000 --- a/util/iobuf.c +++ /dev/null @@ -1,2276 +0,0 @@ -/* iobuf.c - file handling - * Copyright (C) 1998, 1999, 2000, 2001, 2003, - * 2004 Free Software Foundation, Inc. - * - * This file is part of GnuPG. - * - * GnuPG is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * GnuPG is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, - * USA. - */ - -#include <config.h> -#include <stdio.h> -#include <stdlib.h> -#include <string.h> -#include <errno.h> -#include <ctype.h> -#include <assert.h> -#include <sys/types.h> -#include <sys/stat.h> -#include <fcntl.h> -#include <unistd.h> -#ifdef HAVE_DOSISH_SYSTEM -#include <windows.h> -#endif -#ifdef __riscos__ -#include <kernel.h> -#include <swis.h> -#endif /* __riscos__ */ - -#include "memory.h" -#include "util.h" -#include "dynload.h" -#include "iobuf.h" - -/* The size of the internal buffers. - NOTE: If you change this value you MUST also adjust the regression - test "armored_key_8192" in armor.test! */ -#define IOBUF_BUFFER_SIZE 8192 - - -#undef FILE_FILTER_USES_STDIO - -#ifdef HAVE_DOSISH_SYSTEM -#define USE_SETMODE 1 -#endif - -#ifdef FILE_FILTER_USES_STDIO -#define my_fileno(a) fileno ((a)) -#define my_fopen_ro(a,b) fopen ((a),(b)) -#define my_fopen(a,b) fopen ((a),(b)) -typedef FILE *FILEP_OR_FD; -#define INVALID_FP NULL -#define FILEP_OR_FD_FOR_STDIN (stdin) -#define FILEP_OR_FD_FOR_STDOUT (stdout) -typedef struct { - FILE *fp; /* open file handle */ - int keep_open; - int no_cache; - int print_only_name; /* flags indicating that fname is not a real file*/ - char fname[1]; /* name of the file */ - } file_filter_ctx_t ; -#else -#define my_fileno(a) (a) -#define my_fopen_ro(a,b) fd_cache_open ((a),(b)) -#define my_fopen(a,b) direct_open ((a),(b)) -#ifdef HAVE_DOSISH_SYSTEM -typedef HANDLE FILEP_OR_FD; -#define INVALID_FP ((HANDLE)-1) -#define FILEP_OR_FD_FOR_STDIN (GetStdHandle (STD_INPUT_HANDLE)) -#define FILEP_OR_FD_FOR_STDOUT (GetStdHandle (STD_OUTPUT_HANDLE)) -#undef USE_SETMODE -#else -typedef int FILEP_OR_FD; -#define INVALID_FP (-1) -#define FILEP_OR_FD_FOR_STDIN (0) -#define FILEP_OR_FD_FOR_STDOUT (1) -#endif -typedef struct { - FILEP_OR_FD fp; /* open file handle */ - int keep_open; - int no_cache; - int eof_seen; - int print_only_name; /* flags indicating that fname is not a real file*/ - char fname[1]; /* name of the file */ - } file_filter_ctx_t ; - - struct close_cache_s { - struct close_cache_s *next; - FILEP_OR_FD fp; - char fname[1]; - }; - typedef struct close_cache_s *CLOSE_CACHE; - static CLOSE_CACHE close_cache; -#endif - -#ifdef _WIN32 -typedef struct { - int sock; - int keep_open; - int no_cache; - int eof_seen; - int print_only_name; /* flags indicating that fname is not a real file*/ - char fname[1]; /* name of the file */ -} sock_filter_ctx_t ; -#endif /*_WIN32*/ - -/* The first partial length header block must be of size 512 - * to make it easier (and efficienter) we use a min. block size of 512 - * for all chunks (but the last one) */ -#define OP_MIN_PARTIAL_CHUNK 512 -#define OP_MIN_PARTIAL_CHUNK_2POW 9 - -typedef struct { - int use; - size_t size; - size_t count; - int partial; /* 1 = partial header, 2 in last partial packet */ - char *buffer; /* used for partial header */ - size_t buflen; /* used size of buffer */ - int first_c; /* of partial header (which is > 0)*/ - int eof; -} block_filter_ctx_t; - -static int special_names_enabled; - -static int underflow(IOBUF a); -static int translate_file_handle ( int fd, int for_write ); - - - -#ifndef FILE_FILTER_USES_STDIO - -/* This is a replacement for strcmp. Under W32 it does not - distinguish between backslash and slash. */ -static int -fd_cache_strcmp (const char *a, const char *b) -{ -#ifdef HAVE_DOSISH_SYSTEM - for (; *a && *b; a++, b++) - { - if (*a != *b && !((*a == '/' && *b == '\\') - || (*a == '\\' && *b == '/')) ) - break; - } - return *(const unsigned char *)a - *(const unsigned char *)b; -#else - return strcmp (a, b); -#endif -} - -/* - * Invalidate (i.e. close) a cached iobuf or all iobufs if NULL is - * used for FNAME. - */ -static void -fd_cache_invalidate (const char *fname) -{ - CLOSE_CACHE cc; - - if (!fname) { - if( DBG_IOBUF ) - log_debug ("fd_cache_invalidate (all)\n"); - - for (cc=close_cache; cc; cc = cc->next ) { - if ( cc->fp != INVALID_FP ) { -#ifdef HAVE_DOSISH_SYSTEM - CloseHandle (cc->fp); -#else - close(cc->fp); -#endif - cc->fp = INVALID_FP; - } - } - return; - } - - if( DBG_IOBUF ) - log_debug ("fd_cache_invalidate (%s)\n", fname); - - for (cc=close_cache; cc; cc = cc->next ) { - if ( cc->fp != INVALID_FP && !fd_cache_strcmp (cc->fname, fname) ) { - if( DBG_IOBUF ) - log_debug (" did (%s)\n", cc->fname); -#ifdef HAVE_DOSISH_SYSTEM - CloseHandle (cc->fp); -#else - close(cc->fp); -#endif - cc->fp = INVALID_FP; - } - } -} - - - -static FILEP_OR_FD -direct_open (const char *fname, const char *mode) -{ -#ifdef HAVE_DOSISH_SYSTEM - unsigned long da, cd, sm; - HANDLE hfile; - - /* Note, that we do not handle all mode combinations */ - - /* According to the ReactOS source it seems that open() of the - * standard MSW32 crt does open the file in share mode which is - * something new for MS applications ;-) - */ - if ( strchr (mode, '+') ) { - fd_cache_invalidate (fname); - da = GENERIC_READ|GENERIC_WRITE; - cd = OPEN_EXISTING; - sm = FILE_SHARE_READ | FILE_SHARE_WRITE; - } - else if ( strchr (mode, 'w') ) { - fd_cache_invalidate (fname); - da = GENERIC_WRITE; - cd = CREATE_ALWAYS; - sm = FILE_SHARE_WRITE; - } - else { - da = GENERIC_READ; - cd = OPEN_EXISTING; - sm = FILE_SHARE_READ; - } - - hfile = CreateFile (fname, da, sm, NULL, cd, FILE_ATTRIBUTE_NORMAL, NULL); - return hfile; -#else - int oflag; - int cflag = S_IRUSR|S_IWUSR|S_IRGRP|S_IWGRP|S_IROTH|S_IWOTH; - - /* Note, that we do not handle all mode combinations */ - if ( strchr (mode, '+') ) { - fd_cache_invalidate (fname); - oflag = O_RDWR; - } - else if ( strchr (mode, 'w') ) { - fd_cache_invalidate (fname); - oflag = O_WRONLY | O_CREAT | O_TRUNC; - } - else { - oflag = O_RDONLY; - } -#ifdef O_BINARY - if (strchr (mode, 'b')) - oflag |= O_BINARY; -#endif -#ifndef __riscos__ - return open (fname, oflag, cflag ); -#else - { - struct stat buf; - int rc = stat( fname, &buf ); - - /* Don't allow iobufs on directories */ - if( !rc && S_ISDIR(buf.st_mode) && !S_ISREG(buf.st_mode) ) - return __set_errno( EISDIR ); - else - return open( fname, oflag, cflag ); - } -#endif -#endif -} - - -/* - * Instead of closing an FD we keep it open and cache it for later reuse - * Note that this caching strategy only works if the process does not chdir. - */ -static void -fd_cache_close (const char *fname, FILEP_OR_FD fp) -{ - CLOSE_CACHE cc; - - assert (fp); - if ( !fname || !*fname ) { -#ifdef HAVE_DOSISH_SYSTEM - CloseHandle (fp); -#else - close(fp); -#endif - if( DBG_IOBUF ) - log_debug ("fd_cache_close (%p) real\n", (void*)fp); - return; - } - /* try to reuse a slot */ - for (cc=close_cache; cc; cc = cc->next ) { - if ( cc->fp == INVALID_FP && !fd_cache_strcmp (cc->fname, fname) ) { - cc->fp = fp; - if( DBG_IOBUF ) - log_debug ("fd_cache_close (%s) used existing slot\n", fname); - return; - } - } - /* add a new one */ - if( DBG_IOBUF ) - log_debug ("fd_cache_close (%s) new slot created\n", fname); - cc = xmalloc_clear (sizeof *cc + strlen (fname)); - strcpy (cc->fname, fname); - cc->fp = fp; - cc->next = close_cache; - close_cache = cc; -} - -/* - * Do an direct_open on FNAME but first try to reuse one from the fd_cache - */ -static FILEP_OR_FD -fd_cache_open (const char *fname, const char *mode) -{ - CLOSE_CACHE cc; - - assert (fname); - for (cc=close_cache; cc; cc = cc->next ) { - if ( cc->fp != INVALID_FP && !fd_cache_strcmp (cc->fname, fname) ) { - FILEP_OR_FD fp = cc->fp; - cc->fp = INVALID_FP; - if( DBG_IOBUF ) - log_debug ("fd_cache_open (%s) using cached fp\n", fname); -#ifdef HAVE_DOSISH_SYSTEM - if (SetFilePointer (fp, 0, NULL, FILE_BEGIN) == 0xffffffff ) { - log_error ("rewind file failed on handle %p: %s\n", - fp, w32_strerror (errno)); - fp = INVALID_FP; - } -#else - if ( lseek (fp, 0, SEEK_SET) == (off_t)-1 ) { - log_error("can't rewind fd %d: %s\n", fp, strerror(errno) ); - fp = INVALID_FP; - } -#endif - return fp; - } - } - if( DBG_IOBUF ) - log_debug ("fd_cache_open (%s) not cached\n", fname); - return direct_open (fname, mode); -} - - -#endif /*FILE_FILTER_USES_STDIO*/ - - -/**************** - * Read data from a file into buf which has an allocated length of *LEN. - * return the number of read bytes in *LEN. OPAQUE is the FILE * of - * the stream. A is not used. - * control may be: - * IOBUFCTRL_INIT: called just before the function is linked into the - * list of function. This can be used to prepare internal - * data structures of the function. - * IOBUFCTRL_FREE: called just before the function is removed from the - * list of functions and can be used to release internal - * data structures or close a file etc. - * IOBUFCTRL_UNDERFLOW: called by iobuf_underflow to fill the buffer - * with new stuff. *RET_LEN is the available size of the - * buffer, and should be set to the number of bytes - * which were put into the buffer. The function - * returns 0 to indicate success, -1 on EOF and - * G10ERR_xxxxx for other errors. - * - * IOBUFCTRL_FLUSH: called by iobuf_flush() to write out the collected stuff. - * *RET_LAN is the number of bytes in BUF. - * - * IOBUFCTRL_CANCEL: send to all filters on behalf of iobuf_cancel. The - * filter may take appropriate action on this message. - */ -static int -file_filter(void *opaque, int control, IOBUF chain, byte *buf, size_t *ret_len) -{ - file_filter_ctx_t *a = opaque; - FILEP_OR_FD f = a->fp; - size_t size = *ret_len; - size_t nbytes = 0; - int rc = 0; - -#ifdef FILE_FILTER_USES_STDIO - if( control == IOBUFCTRL_UNDERFLOW ) { - assert( size ); /* need a buffer */ - if ( feof(f)) { /* On terminals you could easiely read as many EOFs as you call */ - rc = -1; /* fread() or fgetc() repeatly. Every call will block until you press */ - *ret_len = 0; /* CTRL-D. So we catch this case before we call fread() again. */ - } - else { - clearerr( f ); - nbytes = fread( buf, 1, size, f ); - if( feof(f) && !nbytes ) { - rc = -1; /* okay: we can return EOF now. */ - } - else if( ferror(f) && errno != EPIPE ) { - log_error("%s: read error: %s\n", - a->fname, strerror(errno)); - rc = G10ERR_READ_FILE; - } - *ret_len = nbytes; - } - } - else if( control == IOBUFCTRL_FLUSH ) { - if( size ) { - clearerr( f ); - nbytes = fwrite( buf, 1, size, f ); - if( ferror(f) ) { - log_error("%s: write error: %s\n", a->fname, strerror(errno)); - rc = G10ERR_WRITE_FILE; - } - } - *ret_len = nbytes; - } - else if( control == IOBUFCTRL_INIT ) { - a->keep_open = a->no_cache = 0; - } - else if( control == IOBUFCTRL_DESC ) { - *(char**)buf = "file_filter"; - } - else if( control == IOBUFCTRL_FREE ) { - if( f != stdin && f != stdout ) { - if( DBG_IOBUF ) - log_debug("%s: close fd %d\n", a->fname, fileno(f) ); - if (!a->keep_open) - fclose(f); - } - f = NULL; - xfree(a); /* we can free our context now */ - } -#else /* !stdio implementation */ - - if( control == IOBUFCTRL_UNDERFLOW ) { - assert( size ); /* need a buffer */ - if ( a->eof_seen) { - rc = -1; - *ret_len = 0; - } - else { -#ifdef HAVE_DOSISH_SYSTEM - unsigned long nread; - - nbytes = 0; - if ( !ReadFile ( f, buf, size, &nread, NULL ) ) { - if ((int)GetLastError () != ERROR_BROKEN_PIPE) { - log_error ("%s: read error: %s\n", a->fname, - w32_strerror (0)); - rc = G10ERR_READ_FILE; - } - } - else if ( !nread ) { - a->eof_seen = 1; - rc = -1; - } - else { - nbytes = nread; - } - -#else - - int n; - - nbytes = 0; - do { - n = read ( f, buf, size ); - } while (n == -1 && errno == EINTR ); - if ( n == -1 ) { /* error */ - if (errno != EPIPE) { - log_error("%s: read error: %s\n", - a->fname, strerror(errno)); - rc = G10ERR_READ_FILE; - } - } - else if ( !n ) { /* eof */ - a->eof_seen = 1; - rc = -1; - } - else { - nbytes = n; - } -#endif - *ret_len = nbytes; - } - } - else if( control == IOBUFCTRL_FLUSH ) { - if( size ) { -#ifdef HAVE_DOSISH_SYSTEM - byte *p = buf; - unsigned long n; - - nbytes = size; - do { - if (size && !WriteFile (f, p, nbytes, &n, NULL)) { - log_error ("%s: write error: %s\n", a->fname, - w32_strerror (0)); - rc = G10ERR_WRITE_FILE; - break; - } - p += n; - nbytes -= n; - } while ( nbytes ); - nbytes = p - buf; -#else - byte *p = buf; - int n; - - nbytes = size; - do { - do { - n = write ( f, p, nbytes ); - } while ( n == -1 && errno == EINTR ); - if ( n > 0 ) { - p += n; - nbytes -= n; - } - } while ( n != -1 && nbytes ); - if( n == -1 ) { - log_error("%s: write error: %s\n", a->fname, strerror(errno)); - rc = G10ERR_WRITE_FILE; - } - nbytes = p - buf; -#endif - } - *ret_len = nbytes; - } - else if ( control == IOBUFCTRL_INIT ) { - a->eof_seen = 0; - a->keep_open = 0; - a->no_cache = 0; - } - else if ( control == IOBUFCTRL_DESC ) { - *(char**)buf = "file_filter(fd)"; - } - else if ( control == IOBUFCTRL_FREE ) { -#ifdef HAVE_DOSISH_SYSTEM - if ( f != FILEP_OR_FD_FOR_STDIN && f != FILEP_OR_FD_FOR_STDOUT ) { - if( DBG_IOBUF ) - log_debug("%s: close handle %p\n", a->fname, f ); - if (!a->keep_open) - fd_cache_close (a->no_cache?NULL:a->fname, f); - } -#else - if ( (int)f != 0 && (int)f != 1 ) { - if( DBG_IOBUF ) - log_debug("%s: close fd %d\n", a->fname, f ); - if (!a->keep_open) - fd_cache_close (a->no_cache?NULL:a->fname, f); - } - f = INVALID_FP; -#endif - xfree (a); /* we can free our context now */ - } -#endif /* !stdio implementation */ - return rc; -} - -#ifdef _WIN32 -/* Becuase sockets are an special object under Lose32 we have to - * use a special filter */ -static int -sock_filter (void *opaque, int control, IOBUF chain, byte *buf, size_t *ret_len) -{ - sock_filter_ctx_t *a = opaque; - size_t size = *ret_len; - size_t nbytes = 0; - int rc = 0; - - if( control == IOBUFCTRL_UNDERFLOW ) { - assert( size ); /* need a buffer */ - if ( a->eof_seen) { - rc = -1; - *ret_len = 0; - } - else { - int nread; - - nread = recv ( a->sock, buf, size, 0 ); - if ( nread == SOCKET_ERROR ) { - int ec = (int)WSAGetLastError (); - log_error("socket read error: ec=%d\n", ec); - rc = G10ERR_READ_FILE; - } - else if ( !nread ) { - a->eof_seen = 1; - rc = -1; - } - else { - nbytes = nread; - } - *ret_len = nbytes; - } - } - else if( control == IOBUFCTRL_FLUSH ) { - if( size ) { - byte *p = buf; - int n; - - nbytes = size; - do { - n = send (a->sock, p, nbytes, 0); - if ( n == SOCKET_ERROR ) { - int ec = (int)WSAGetLastError (); - log_error("socket write error: ec=%d\n", ec); - rc = G10ERR_WRITE_FILE; - break; - } - p += n; - nbytes -= n; - } while ( nbytes ); - nbytes = p - buf; - } - *ret_len = nbytes; - } - else if ( control == IOBUFCTRL_INIT ) { - a->eof_seen = 0; - a->keep_open = 0; - a->no_cache = 0; - } - else if ( control == IOBUFCTRL_DESC ) { - *(char**)buf = "sock_filter"; - } - else if ( control == IOBUFCTRL_FREE ) { - if (!a->keep_open) - closesocket (a->sock); - xfree (a); /* we can free our context now */ - } - return rc; -} -#endif /*_WIN32*/ - -/**************** - * This is used to implement the block write mode. - * Block reading is done on a byte by byte basis in readbyte(), - * without a filter - */ -static int -block_filter(void *opaque, int control, IOBUF chain, byte *buf, size_t *ret_len) -{ - block_filter_ctx_t *a = opaque; - size_t size = *ret_len; - int c, needed, rc = 0; - char *p; - - if( control == IOBUFCTRL_UNDERFLOW ) { - size_t n=0; - - p = buf; - assert( size ); /* need a buffer */ - if( a->eof ) /* don't read any further */ - rc = -1; - while( !rc && size ) { - if( !a->size ) { /* get the length bytes */ - if( a->partial == 2 ) { - a->eof = 1; - if( !n ) - rc = -1; - break; - } - else if( a->partial ) { - /* These OpenPGP introduced huffman like encoded length - * bytes are really a mess :-( */ - if( a->first_c ) { - c = a->first_c; - a->first_c = 0; - } - else if( (c = iobuf_get(chain)) == -1 ) { - log_error("block_filter: 1st length byte missing\n"); - rc = G10ERR_READ_FILE; - break; - } - if( c < 192 ) { - a->size = c; - a->partial = 2; - if( !a->size ) { - a->eof = 1; - if( !n ) - rc = -1; - break; - } - } - else if( c < 224 ) { - a->size = (c - 192) * 256; - if( (c = iobuf_get(chain)) == -1 ) { - log_error("block_filter: 2nd length byte missing\n"); - rc = G10ERR_READ_FILE; - break; - } - a->size += c + 192; - a->partial = 2; - if( !a->size ) { - a->eof = 1; - if( !n ) - rc = -1; - break; - } - } - else if( c == 255 ) { - a->size = iobuf_get(chain) << 24; - a->size |= iobuf_get(chain) << 16; - a->size |= iobuf_get(chain) << 8; - if( (c = iobuf_get(chain)) == -1 ) { - log_error("block_filter: invalid 4 byte length\n"); - rc = G10ERR_READ_FILE; - break; - } - a->size |= c; - a->partial = 2; - if( !a->size ) { - a->eof = 1; - if( !n ) - rc = -1; - break; - } - } - else { /* next partial body length */ - a->size = 1 << (c & 0x1f); - } - /* log_debug("partial: ctx=%p c=%02x size=%u\n", a, c, a->size);*/ - } - else - BUG(); - } - - while( !rc && size && a->size ) { - needed = size < a->size ? size : a->size; - c = iobuf_read( chain, p, needed ); - if( c < needed ) { - if( c == -1 ) c = 0; - log_error("block_filter %p: read error (size=%lu,a->size=%lu)\n", - a, (ulong)size+c, (ulong)a->size+c); - rc = G10ERR_READ_FILE; - } - else { - size -= c; - a->size -= c; - p += c; - n += c; - } - } - } - *ret_len = n; - } - else if( control == IOBUFCTRL_FLUSH ) { - if( a->partial ) { /* the complicated openpgp scheme */ - size_t blen, n, nbytes = size + a->buflen; - - assert( a->buflen <= OP_MIN_PARTIAL_CHUNK ); - if( nbytes < OP_MIN_PARTIAL_CHUNK ) { - /* not enough to write a partial block out; so we store it*/ - if( !a->buffer ) - a->buffer = xmalloc( OP_MIN_PARTIAL_CHUNK ); - memcpy( a->buffer + a->buflen, buf, size ); - a->buflen += size; - } - else { /* okay, we can write out something */ - /* do this in a loop to use the most efficient block lengths */ - p = buf; - do { - /* find the best matching block length - this is limited - * by the size of the internal buffering */ - for( blen=OP_MIN_PARTIAL_CHUNK*2, - c=OP_MIN_PARTIAL_CHUNK_2POW+1; blen <= nbytes; - blen *=2, c++ ) - ; - blen /= 2; c--; - /* write the partial length header */ - assert( c <= 0x1f ); /*;-)*/ - c |= 0xe0; - iobuf_put( chain, c ); - if( (n=a->buflen) ) { /* write stuff from the buffer */ - assert( n == OP_MIN_PARTIAL_CHUNK); - if( iobuf_write(chain, a->buffer, n ) ) - rc = G10ERR_WRITE_FILE; - a->buflen = 0; - nbytes -= n; - } - if( (n = nbytes) > blen ) - n = blen; - if( n && iobuf_write(chain, p, n ) ) - rc = G10ERR_WRITE_FILE; - p += n; - nbytes -= n; - } while( !rc && nbytes >= OP_MIN_PARTIAL_CHUNK ); - /* store the rest in the buffer */ - if( !rc && nbytes ) { - assert( !a->buflen ); - assert( nbytes < OP_MIN_PARTIAL_CHUNK ); - if( !a->buffer ) - a->buffer = xmalloc( OP_MIN_PARTIAL_CHUNK ); - memcpy( a->buffer, p, nbytes ); - a->buflen = nbytes; - } - } - } - else - BUG(); - } - else if( control == IOBUFCTRL_INIT ) { - if( DBG_IOBUF ) - log_debug("init block_filter %p\n", a ); - if( a->partial ) - a->count = 0; - else if( a->use == 1 ) - a->count = a->size = 0; - else - a->count = a->size; /* force first length bytes */ - a->eof = 0; - a->buffer = NULL; - a->buflen = 0; - } - else if( control == IOBUFCTRL_DESC ) { - *(char**)buf = "block_filter"; - } - else if( control == IOBUFCTRL_FREE ) { - if( a->use == 2 ) { /* write the end markers */ - if( a->partial ) { - u32 len; - /* write out the remaining bytes without a partial header - * the length of this header may be 0 - but if it is - * the first block we are not allowed to use a partial header - * and frankly we can't do so, because this length must be - * a power of 2. This is _really_ complicated because we - * have to check the possible length of a packet prior - * to it's creation: a chain of filters becomes complicated - * and we need a lot of code to handle compressed packets etc. - * :-((((((( - */ - /* construct header */ - len = a->buflen; - /*log_debug("partial: remaining length=%u\n", len );*/ - if( len < 192 ) - rc = iobuf_put(chain, len ); - else if( len < 8384 ) { - if( !(rc=iobuf_put( chain, ((len-192) / 256) + 192)) ) - rc = iobuf_put( chain, ((len-192) % 256)); - } - else { /* use a 4 byte header */ - if( !(rc=iobuf_put( chain, 0xff )) ) - if( !(rc=iobuf_put( chain, (len >> 24)&0xff )) ) - if( !(rc=iobuf_put( chain, (len >> 16)&0xff )) ) - if( !(rc=iobuf_put( chain, (len >> 8)&0xff ))) - rc=iobuf_put( chain, len & 0xff ); - } - if( !rc && len ) - rc = iobuf_write(chain, a->buffer, len ); - if( rc ) { - log_error("block_filter: write error: %s\n",strerror(errno)); - rc = G10ERR_WRITE_FILE; - } - xfree( a->buffer ); a->buffer = NULL; a->buflen = 0; - } - else - BUG(); - } - else if( a->size ) { - log_error("block_filter: pending bytes!\n"); - } - if( DBG_IOBUF ) - log_debug("free block_filter %p\n", a ); - xfree(a); /* we can free our context now */ - } - - return rc; -} - - -static void -print_chain( IOBUF a ) -{ - if( !DBG_IOBUF ) - return; - for(; a; a = a->chain ) { - size_t dummy_len = 0; - const char *desc = "[none]"; - - if( a->filter ) - a->filter( a->filter_ov, IOBUFCTRL_DESC, NULL, - (byte*)&desc, &dummy_len ); - - log_debug("iobuf chain: %d.%d `%s' filter_eof=%d start=%d len=%d\n", - a->no, a->subno, desc, a->filter_eof, - (int)a->d.start, (int)a->d.len ); - } -} - -int -iobuf_print_chain( IOBUF a ) -{ - print_chain(a); - return 0; -} - -/**************** - * Allocate a new io buffer, with no function assigned. - * Use is the desired usage: 1 for input, 2 for output, 3 for temp buffer - * BUFSIZE is a suggested buffer size. - */ -IOBUF -iobuf_alloc(int use, size_t bufsize) -{ - IOBUF a; - static int number=0; - - a = xmalloc_clear(sizeof *a); - a->use = use; - a->d.buf = xmalloc( bufsize ); - a->d.size = bufsize; - a->no = ++number; - a->subno = 0; - a->opaque = NULL; - a->real_fname = NULL; - return a; -} - -int -iobuf_close ( IOBUF a ) -{ - IOBUF a2; - size_t dummy_len=0; - int rc=0; - - if( a && a->directfp ) { - fclose( a->directfp ); - xfree( a->real_fname ); - if( DBG_IOBUF ) - log_debug("iobuf_close -> %p\n", a->directfp ); - return 0; - } - - for( ; a && !rc ; a = a2 ) { - a2 = a->chain; - if( a->use == 2 && (rc=iobuf_flush(a)) ) - log_error("iobuf_flush failed on close: %s\n", g10_errstr(rc)); - - if( DBG_IOBUF ) - log_debug("iobuf-%d.%d: close `%s'\n", a->no, a->subno, a->desc ); - if( a->filter && (rc = a->filter(a->filter_ov, IOBUFCTRL_FREE, - a->chain, NULL, &dummy_len)) ) - log_error("IOBUFCTRL_FREE failed on close: %s\n", g10_errstr(rc) ); - xfree(a->real_fname); - if (a->d.buf) { - memset (a->d.buf, 0, a->d.size); /* erase the buffer */ - xfree(a->d.buf); - } - xfree(a); - } - return rc; -} - -int -iobuf_cancel( IOBUF a ) -{ - const char *s; - IOBUF a2; - int rc; -#if defined(HAVE_DOSISH_SYSTEM) || defined(__riscos__) - char *remove_name = NULL; -#endif - - if( a && a->use == 2 ) { - s = iobuf_get_real_fname(a); - if( s && *s ) { -#if defined(HAVE_DOSISH_SYSTEM) || defined(__riscos__) - remove_name = xstrdup ( s ); -#else - remove(s); -#endif - } - } - - /* send a cancel message to all filters */ - for( a2 = a; a2 ; a2 = a2->chain ) { - size_t dummy; - if( a2->filter ) - a2->filter( a2->filter_ov, IOBUFCTRL_CANCEL, a2->chain, - NULL, &dummy ); - } - - rc = iobuf_close(a); -#if defined(HAVE_DOSISH_SYSTEM) || defined(__riscos__) - if ( remove_name ) { - /* Argg, MSDOS does not allow to remove open files. So - * we have to do it here */ - remove ( remove_name ); - xfree ( remove_name ); - } -#endif - return rc; -} - - -/**************** - * create a temporary iobuf, which can be used to collect stuff - * in an iobuf and later be written by iobuf_write_temp() to another - * iobuf. - */ -IOBUF -iobuf_temp() -{ - IOBUF a; - - a = iobuf_alloc(3, IOBUF_BUFFER_SIZE ); - - return a; -} - -IOBUF -iobuf_temp_with_content( const char *buffer, size_t length ) -{ - IOBUF a; - - a = iobuf_alloc(3, length ); - memcpy( a->d.buf, buffer, length ); - a->d.len = length; - - return a; -} - -void -iobuf_enable_special_filenames ( int yes ) -{ - special_names_enabled = yes; -} - -/* - * see whether the filename has the for "-&nnnn", where n is a - * non-zero number. - * Returns this number or -1 if it is not the case. - */ -static int -check_special_filename ( const char *fname ) -{ - if ( special_names_enabled - && fname && *fname == '-' && fname[1] == '&' ) { - int i; - - fname += 2; - for (i=0; digitp (fname+i); i++ ) - ; - if ( !fname[i] ) - return atoi (fname); - } - return -1; -} - -/* This fucntion returns true if FNAME indicates a PIPE (stdout or - stderr) or a special file name if those are enabled. */ -int -iobuf_is_pipe_filename (const char *fname) -{ - if (!fname || (*fname=='-' && !fname[1]) ) - return 1; - return check_special_filename (fname) != -1; -} - -/**************** - * Create a head iobuf for reading from a file - * returns: NULL if an error occures and sets errno - */ -IOBUF -iobuf_open( const char *fname ) -{ - IOBUF a; - FILEP_OR_FD fp; - file_filter_ctx_t *fcx; - size_t len; - int print_only = 0; - int fd; - - if( !fname || (*fname=='-' && !fname[1]) ) { - fp = FILEP_OR_FD_FOR_STDIN; -#ifdef USE_SETMODE - setmode ( my_fileno(fp) , O_BINARY ); -#endif - fname = "[stdin]"; - print_only = 1; - } - else if ( (fd = check_special_filename ( fname )) != -1 ) - return iobuf_fdopen ( translate_file_handle (fd,0), "rb" ); - else if( (fp = my_fopen_ro(fname, "rb")) == INVALID_FP ) - return NULL; - a = iobuf_alloc(1, IOBUF_BUFFER_SIZE ); - fcx = xmalloc( sizeof *fcx + strlen(fname) ); - fcx->fp = fp; - fcx->print_only_name = print_only; - strcpy(fcx->fname, fname ); - if( !print_only ) - a->real_fname = xstrdup( fname ); - a->filter = file_filter; - a->filter_ov = fcx; - file_filter( fcx, IOBUFCTRL_DESC, NULL, (byte*)&a->desc, &len ); - file_filter( fcx, IOBUFCTRL_INIT, NULL, NULL, &len ); - if( DBG_IOBUF ) - log_debug("iobuf-%d.%d: open `%s' fd=%d\n", - a->no, a->subno, fname, (int)my_fileno(fcx->fp) ); - - return a; -} - -/**************** - * Create a head iobuf for reading from a file - * returns: NULL if an error occures and sets errno - */ -IOBUF -iobuf_fdopen( int fd, const char *mode ) -{ - IOBUF a; - FILEP_OR_FD fp; - file_filter_ctx_t *fcx; - size_t len; - -#ifdef FILE_FILTER_USES_STDIO - if( !(fp = fdopen(fd, mode)) ) - return NULL; -#else - fp = (FILEP_OR_FD)fd; -#endif - a = iobuf_alloc( strchr( mode, 'w')? 2:1, IOBUF_BUFFER_SIZE ); - fcx = xmalloc( sizeof *fcx + 20 ); - fcx->fp = fp; - fcx->print_only_name = 1; - sprintf(fcx->fname, "[fd %d]", fd ); - a->filter = file_filter; - a->filter_ov = fcx; - file_filter( fcx, IOBUFCTRL_DESC, NULL, (byte*)&a->desc, &len ); - file_filter( fcx, IOBUFCTRL_INIT, NULL, NULL, &len ); - if( DBG_IOBUF ) - log_debug("iobuf-%d.%d: fdopen `%s'\n", a->no, a->subno, fcx->fname ); - iobuf_ioctl (a,3,1,NULL); /* disable fd caching */ - return a; -} - - -IOBUF -iobuf_sockopen ( int fd, const char *mode ) -{ - IOBUF a; -#ifdef _WIN32 - sock_filter_ctx_t *scx; - size_t len; - - a = iobuf_alloc( strchr( mode, 'w')? 2:1, IOBUF_BUFFER_SIZE ); - scx = xmalloc( sizeof *scx + 25 ); - scx->sock = fd; - scx->print_only_name = 1; - sprintf(scx->fname, "[sock %d]", fd ); - a->filter = sock_filter; - a->filter_ov = scx; - sock_filter( scx, IOBUFCTRL_DESC, NULL, (byte*)&a->desc, &len ); - sock_filter( scx, IOBUFCTRL_INIT, NULL, NULL, &len ); - if( DBG_IOBUF ) - log_debug("iobuf-%d.%d: sockopen `%s'\n", a->no, a->subno, scx->fname); - iobuf_ioctl (a,3,1,NULL); /* disable fd caching */ -#else - a = iobuf_fdopen (fd, mode); -#endif - return a; -} - -/**************** - * create an iobuf for writing to a file; the file will be created. - */ -IOBUF -iobuf_create( const char *fname ) -{ - IOBUF a; - FILEP_OR_FD fp; - file_filter_ctx_t *fcx; - size_t len; - int print_only = 0; - int fd; - - if( !fname || (*fname=='-' && !fname[1]) ) { - fp = FILEP_OR_FD_FOR_STDOUT; -#ifdef USE_SETMODE - setmode ( my_fileno(fp) , O_BINARY ); -#endif - fname = "[stdout]"; - print_only = 1; - } - else if ( (fd = check_special_filename ( fname )) != -1 ) - return iobuf_fdopen ( translate_file_handle (fd, 1), "wb" ); - else if( (fp = my_fopen(fname, "wb")) == INVALID_FP ) - return NULL; - a = iobuf_alloc(2, IOBUF_BUFFER_SIZE ); - fcx = xmalloc( sizeof *fcx + strlen(fname) ); - fcx->fp = fp; - fcx->print_only_name = print_only; - strcpy(fcx->fname, fname ); - if( !print_only ) - a->real_fname = xstrdup( fname ); - a->filter = file_filter; - a->filter_ov = fcx; - file_filter( fcx, IOBUFCTRL_DESC, NULL, (byte*)&a->desc, &len ); - file_filter( fcx, IOBUFCTRL_INIT, NULL, NULL, &len ); - if( DBG_IOBUF ) - log_debug("iobuf-%d.%d: create `%s'\n", a->no, a->subno, a->desc ); - - return a; -} - -/**************** - * append to an iobuf; if the file does not exist, create it. - * cannot be used for stdout. - * Note: This is not used. - */ -#if 0 /* not used */ -IOBUF -iobuf_append( const char *fname ) -{ - IOBUF a; - FILE *fp; - file_filter_ctx_t *fcx; - size_t len; - - if( !fname ) - return NULL; - else if( !(fp = my_fopen(fname, "ab")) ) - return NULL; - a = iobuf_alloc(2, IOBUF_BUFFER_SIZE ); - fcx = xmalloc( sizeof *fcx + strlen(fname) ); - fcx->fp = fp; - strcpy(fcx->fname, fname ); - a->real_fname = xstrdup( fname ); - a->filter = file_filter; - a->filter_ov = fcx; - file_filter( fcx, IOBUFCTRL_DESC, NULL, (byte*)&a->desc, &len ); - file_filter( fcx, IOBUFCTRL_INIT, NULL, NULL, &len ); - if( DBG_IOBUF ) - log_debug("iobuf-%d.%d: append `%s'\n", a->no, a->subno, a->desc ); - - return a; -} -#endif - -IOBUF -iobuf_openrw( const char *fname ) -{ - IOBUF a; - FILEP_OR_FD fp; - file_filter_ctx_t *fcx; - size_t len; - - if( !fname ) - return NULL; - else if( (fp = my_fopen(fname, "r+b")) == INVALID_FP ) - return NULL; - a = iobuf_alloc(2, IOBUF_BUFFER_SIZE ); - fcx = xmalloc( sizeof *fcx + strlen(fname) ); - fcx->fp = fp; - strcpy(fcx->fname, fname ); - a->real_fname = xstrdup( fname ); - a->filter = file_filter; - a->filter_ov = fcx; - file_filter( fcx, IOBUFCTRL_DESC, NULL, (byte*)&a->desc, &len ); - file_filter( fcx, IOBUFCTRL_INIT, NULL, NULL, &len ); - if( DBG_IOBUF ) - log_debug("iobuf-%d.%d: openrw `%s'\n", a->no, a->subno, a->desc ); - - return a; -} - - -int -iobuf_ioctl ( IOBUF a, int cmd, int intval, void *ptrval ) -{ - if ( cmd == 1 ) { /* keep system filepointer/descriptor open */ - if( DBG_IOBUF ) - log_debug("iobuf-%d.%d: ioctl `%s' keep=%d\n", - a? a->no:-1, a?a->subno:-1, a?a->desc:"?", intval ); - for( ; a; a = a->chain ) - if( !a->chain && a->filter == file_filter ) { - file_filter_ctx_t *b = a->filter_ov; - b->keep_open = intval; - return 0; - } -#ifdef _WIN32 - else if( !a->chain && a->filter == sock_filter ) { - sock_filter_ctx_t *b = a->filter_ov; - b->keep_open = intval; - return 0; - } -#endif - } - else if ( cmd == 2 ) { /* invalidate cache */ - if( DBG_IOBUF ) - log_debug("iobuf-*.*: ioctl `%s' invalidate\n", - ptrval? (char*)ptrval:"[all]"); - if ( !a && !intval ) { -#ifndef FILE_FILTER_USES_STDIO - fd_cache_invalidate (ptrval); -#endif - return 0; - } - } - else if ( cmd == 3 ) { /* disallow/allow caching */ - if( DBG_IOBUF ) - log_debug("iobuf-%d.%d: ioctl `%s' no_cache=%d\n", - a? a->no:-1, a?a->subno:-1, a?a->desc:"?", intval ); - for( ; a; a = a->chain ) - if( !a->chain && a->filter == file_filter ) { - file_filter_ctx_t *b = a->filter_ov; - b->no_cache = intval; - return 0; - } -#ifdef _WIN32 - else if( !a->chain && a->filter == sock_filter ) { - sock_filter_ctx_t *b = a->filter_ov; - b->no_cache = intval; - return 0; - } -#endif - } - - return -1; -} - - -/**************** - * Register an i/o filter. - */ -int -iobuf_push_filter( IOBUF a, - int (*f)(void *opaque, int control, - IOBUF chain, byte *buf, size_t *len), void *ov ) -{ - return iobuf_push_filter2( a, f, ov, 0 ); -} - -int -iobuf_push_filter2( IOBUF a, - int (*f)(void *opaque, int control, - IOBUF chain, byte *buf, size_t *len), - void *ov, int rel_ov ) -{ - IOBUF b; - size_t dummy_len=0; - int rc=0; - - if( a->directfp ) - BUG(); - - if( a->use == 2 && (rc=iobuf_flush(a)) ) - return rc; - /* make a copy of the current stream, so that - * A is the new stream and B the original one. - * The contents of the buffers are transferred to the - * new stream. - */ - b = xmalloc(sizeof *b); - memcpy(b, a, sizeof *b ); - /* fixme: it is stupid to keep a copy of the name at every level - * but we need the name somewhere because the name known by file_filter - * may have been released when we need the name of the file */ - b->real_fname = a->real_fname? xstrdup(a->real_fname):NULL; - /* remove the filter stuff from the new stream */ - a->filter = NULL; - a->filter_ov = NULL; - a->filter_ov_owner = 0; - a->filter_eof = 0; - if( a->use == 3 ) - a->use = 2; /* make a write stream from a temp stream */ - - if( a->use == 2 ) { /* allocate a fresh buffer for the original stream */ - b->d.buf = xmalloc( a->d.size ); - b->d.len = 0; - b->d.start = 0; - } - else { /* allocate a fresh buffer for the new stream */ - a->d.buf = xmalloc( a->d.size ); - a->d.len = 0; - a->d.start = 0; - } - /* disable nlimit for the new stream */ - a->ntotal = b->ntotal + b->nbytes; - a->nlimit = a->nbytes = 0; - a->nofast &= ~1; - /* make a link from the new stream to the original stream */ - a->chain = b; - a->opaque = b->opaque; - - /* setup the function on the new stream */ - a->filter = f; - a->filter_ov = ov; - a->filter_ov_owner = rel_ov; - - a->subno = b->subno + 1; - f( ov, IOBUFCTRL_DESC, NULL, (byte*)&a->desc, &dummy_len ); - - if( DBG_IOBUF ) { - log_debug("iobuf-%d.%d: push `%s'\n", a->no, a->subno, a->desc ); - print_chain( a ); - } - - /* now we can initialize the new function if we have one */ - if( a->filter && (rc = a->filter(a->filter_ov, IOBUFCTRL_INIT, a->chain, - NULL, &dummy_len)) ) - log_error("IOBUFCTRL_INIT failed: %s\n", g10_errstr(rc) ); - return rc; -} - -/**************** - * Remove an i/o filter. - */ -static int -pop_filter( IOBUF a, int (*f)(void *opaque, int control, - IOBUF chain, byte *buf, size_t *len), void *ov ) -{ - IOBUF b; - size_t dummy_len=0; - int rc=0; - - if( a->directfp ) - BUG(); - - if( DBG_IOBUF ) - log_debug("iobuf-%d.%d: pop `%s'\n", a->no, a->subno, a->desc ); - if( !a->filter ) { /* this is simple */ - b = a->chain; - assert(b); - xfree(a->d.buf); - xfree(a->real_fname); - memcpy(a,b, sizeof *a); - xfree(b); - return 0; - } - for(b=a ; b; b = b->chain ) - if( b->filter == f && (!ov || b->filter_ov == ov) ) - break; - if( !b ) - log_bug("pop_filter(): filter function not found\n"); - - /* flush this stream if it is an output stream */ - if( a->use == 2 && (rc=iobuf_flush(b)) ) { - log_error("iobuf_flush failed in pop_filter: %s\n", g10_errstr(rc)); - return rc; - } - /* and tell the filter to free it self */ - if( b->filter && (rc = b->filter(b->filter_ov, IOBUFCTRL_FREE, b->chain, - NULL, &dummy_len)) ) { - log_error("IOBUFCTRL_FREE failed: %s\n", g10_errstr(rc) ); - return rc; - } - if( b->filter_ov && b->filter_ov_owner ) { - xfree( b->filter_ov ); - b->filter_ov = NULL; - } - - - /* and see how to remove it */ - if( a == b && !b->chain ) - log_bug("can't remove the last filter from the chain\n"); - else if( a == b ) { /* remove the first iobuf from the chain */ - /* everything from b is copied to a. This is save because - * a flush has been done on the to be removed entry - */ - b = a->chain; - xfree(a->d.buf); - xfree(a->real_fname); - memcpy(a,b, sizeof *a); - xfree(b); - if( DBG_IOBUF ) - log_debug("iobuf-%d.%d: popped filter\n", a->no, a->subno ); - } - else if( !b->chain ) { /* remove the last iobuf from the chain */ - log_bug("Ohh jeee, trying to remove a head filter\n"); - } - else { /* remove an intermediate iobuf from the chain */ - log_bug("Ohh jeee, trying to remove an intermediate filter\n"); - } - - return rc; -} - - -/**************** - * read underflow: read more bytes into the buffer and return - * the first byte or -1 on EOF. - */ -static int -underflow(IOBUF a) -{ - size_t len; - int rc; - - assert( a->d.start == a->d.len ); - if( a->use == 3 ) - return -1; /* EOF because a temp buffer can't do an underflow */ - - if( a->filter_eof ) { - if( a->chain ) { - IOBUF b = a->chain; - if( DBG_IOBUF ) - log_debug("iobuf-%d.%d: pop `%s' in underflow\n", - a->no, a->subno, a->desc ); - xfree(a->d.buf); - xfree(a->real_fname); - memcpy(a, b, sizeof *a); - xfree(b); - print_chain(a); - } - else - a->filter_eof = 0; /* for the top level filter */ - if( DBG_IOBUF ) - log_debug("iobuf-%d.%d: underflow: eof (due to filter eof)\n", - a->no, a->subno ); - return -1; /* return one(!) EOF */ - } - if( a->error ) { - if( DBG_IOBUF ) - log_debug("iobuf-%d.%d: error\n", a->no, a->subno ); - return -1; - } - - if( a->directfp ) { - FILE *fp = a->directfp; - - len = fread( a->d.buf, 1, a->d.size, fp); - if( len < a->d.size ) { - if( ferror(fp) ) - a->error = 1; - } - a->d.len = len; - a->d.start = 0; - return len? a->d.buf[a->d.start++] : -1; - } - - - if( a->filter ) { - len = a->d.size; - if( DBG_IOBUF ) - log_debug("iobuf-%d.%d: underflow: req=%lu\n", - a->no, a->subno, (ulong)len ); - rc = a->filter( a->filter_ov, IOBUFCTRL_UNDERFLOW, a->chain, - a->d.buf, &len ); - if( DBG_IOBUF ) { - log_debug("iobuf-%d.%d: underflow: got=%lu rc=%d\n", - a->no, a->subno, (ulong)len, rc ); -/* if( a->no == 1 ) */ -/* log_hexdump (" data:", a->d.buf, len); */ - } - if( a->use == 1 && rc == -1 ) { /* EOF: we can remove the filter */ - size_t dummy_len=0; - - /* and tell the filter to free itself */ - if( (rc = a->filter(a->filter_ov, IOBUFCTRL_FREE, a->chain, - NULL, &dummy_len)) ) - log_error("IOBUFCTRL_FREE failed: %s\n", g10_errstr(rc) ); - if( a->filter_ov && a->filter_ov_owner ) { - xfree( a->filter_ov ); - a->filter_ov = NULL; - } - a->filter = NULL; - a->desc = NULL; - a->filter_ov = NULL; - a->filter_eof = 1; - if( !len && a->chain ) { - IOBUF b = a->chain; - if( DBG_IOBUF ) - log_debug("iobuf-%d.%d: pop `%s' in underflow (!len)\n", - a->no, a->subno, a->desc ); - xfree(a->d.buf); - xfree(a->real_fname); - memcpy(a,b, sizeof *a); - xfree(b); - print_chain(a); - } - } - else if( rc ) - a->error = 1; - - if( !len ) { - if( DBG_IOBUF ) - log_debug("iobuf-%d.%d: underflow: eof\n", a->no, a->subno ); - return -1; - } - a->d.len = len; - a->d.start = 0; - return a->d.buf[a->d.start++]; - } - else { - if( DBG_IOBUF ) - log_debug("iobuf-%d.%d: underflow: eof (no filter)\n", - a->no, a->subno ); - return -1; /* no filter; return EOF */ - } -} - - -int -iobuf_flush(IOBUF a) -{ - size_t len; - int rc; - - if( a->directfp ) - return 0; - - if( a->use == 3 ) { /* increase the temp buffer */ - char *newbuf; - size_t newsize = a->d.size + IOBUF_BUFFER_SIZE; - - if( DBG_IOBUF ) - log_debug("increasing temp iobuf from %lu to %lu\n", - (ulong)a->d.size, (ulong)newsize ); - newbuf = xmalloc( newsize ); - memcpy( newbuf, a->d.buf, a->d.len ); - xfree(a->d.buf); - a->d.buf = newbuf; - a->d.size = newsize; - return 0; - } - else if( a->use != 2 ) - log_bug("flush on non-output iobuf\n"); - else if( !a->filter ) - log_bug("iobuf_flush: no filter\n"); - len = a->d.len; - rc = a->filter( a->filter_ov, IOBUFCTRL_FLUSH, a->chain, a->d.buf, &len ); - if( !rc && len != a->d.len ) { - log_info("iobuf_flush did not write all!\n"); - rc = G10ERR_WRITE_FILE; - } - else if( rc ) - a->error = 1; - a->d.len = 0; - - return rc; -} - - -/**************** - * Read a byte from the iobuf; returns -1 on EOF - */ -int -iobuf_readbyte(IOBUF a) -{ - int c; - - /* nlimit does not work together with unget */ - /* nbytes is also not valid! */ - if( a->unget.buf ) { - if( a->unget.start < a->unget.len ) - return a->unget.buf[a->unget.start++]; - xfree(a->unget.buf); - a->unget.buf = NULL; - a->nofast &= ~2; - } - - if( a->nlimit && a->nbytes >= a->nlimit ) - return -1; /* forced EOF */ - - if( a->d.start < a->d.len ) { - c = a->d.buf[a->d.start++]; - } - else if( (c=underflow(a)) == -1 ) - return -1; /* EOF */ - - a->nbytes++; - return c; -} - - -int -iobuf_read(IOBUF a, byte *buf, unsigned buflen ) -{ - int c, n; - - if( a->unget.buf || a->nlimit ) { - /* handle special cases */ - for(n=0 ; n < buflen; n++ ) { - if( (c = iobuf_readbyte(a)) == -1 ) { - if( !n ) - return -1; /* eof */ - break; - } - else - if( buf ) *buf = c; - if( buf ) buf++; - } - return n; - } - - n = 0; - do { - if( n < buflen && a->d.start < a->d.len ) { - unsigned size = a->d.len - a->d.start; - if( size > buflen - n ) - size = buflen - n; - if( buf ) - memcpy( buf, a->d.buf + a->d.start, size ); - n += size; - a->d.start += size; - if( buf ) - buf += size; - } - if( n < buflen ) { - if( (c=underflow(a)) == -1 ) { - a->nbytes += n; - return n? n : -1/*EOF*/; - } - if( buf ) - *buf++ = c; - n++; - } - } while( n < buflen ); - a->nbytes += n; - return n; -} - - -/**************** - * Have a look at the iobuf. - * NOTE: This only works in special cases. - */ -int -iobuf_peek(IOBUF a, byte *buf, unsigned buflen ) -{ - int n=0; - - if( a->filter_eof ) - return -1; - - if( !(a->d.start < a->d.len) ) { - if( underflow(a) == -1 ) - return -1; - /* and unget this character */ - assert(a->d.start == 1); - a->d.start = 0; - } - - for(n=0 ; n < buflen && (a->d.start+n) < a->d.len ; n++, buf++ ) - *buf = a->d.buf[n]; - return n; -} - - - - -int -iobuf_writebyte(IOBUF a, unsigned c) -{ - - if( a->directfp ) - BUG(); - - if( a->d.len == a->d.size ) - if( iobuf_flush(a) ) - return -1; - - assert( a->d.len < a->d.size ); - a->d.buf[a->d.len++] = c; - return 0; -} - - -int -iobuf_write(IOBUF a, byte *buf, unsigned buflen ) -{ - - if( a->directfp ) - BUG(); - - do { - if( buflen && a->d.len < a->d.size ) { - unsigned size = a->d.size - a->d.len; - if( size > buflen ) size = buflen; - memcpy( a->d.buf + a->d.len, buf, size ); - buflen -= size; - buf += size; - a->d.len += size; - } - if( buflen ) { - if( iobuf_flush(a) ) - return -1; - } - } while( buflen ); - return 0; -} - - -int -iobuf_writestr(IOBUF a, const char *buf ) -{ - for( ; *buf; buf++ ) - if( iobuf_writebyte(a, *buf) ) - return -1; - return 0; -} - - - -/**************** - * copy the contents of TEMP to A. - */ -int -iobuf_write_temp( IOBUF a, IOBUF temp ) -{ - while( temp->chain ) - pop_filter( temp, temp->filter, NULL ); - return iobuf_write(a, temp->d.buf, temp->d.len ); -} - -/**************** - * copy the contents of the temp io stream to BUFFER. - */ -size_t -iobuf_temp_to_buffer( IOBUF a, byte *buffer, size_t buflen ) -{ - size_t n = a->d.len; - - if( n > buflen ) - n = buflen; - memcpy( buffer, a->d.buf, n ); - return n; -} - - -/**************** - * Call this function to terminate processing of the temp stream - * without closing it. This removes all filters from the stream - * makes sure that iobuf_get_temp_{buffer,length}() returns correct - * values. - */ -void -iobuf_flush_temp( IOBUF temp ) -{ - while( temp->chain ) - pop_filter( temp, temp->filter, NULL ); -} - - -/**************** - * Set a limit on how many bytes may be read from the input stream A. - * Setting the limit to 0 disables this feature. - */ -void -iobuf_set_limit( IOBUF a, off_t nlimit ) -{ - if( nlimit ) - a->nofast |= 1; - else - a->nofast &= ~1; - a->nlimit = nlimit; - a->ntotal += a->nbytes; - a->nbytes = 0; -} - - - -/* Return the length of an open file A. IF OVERFLOW is not NULL it - will be set to true if the file is larger than what off_t can cope - with. The function return 0 on error or on overflow condition. */ -off_t -iobuf_get_filelength (IOBUF a, int *overflow ) -{ - struct stat st; - - if (overflow) - *overflow = 0; - - if( a->directfp ) { - FILE *fp = a->directfp; - - if( !fstat(fileno(fp), &st) ) - return st.st_size; - log_error("fstat() failed: %s\n", strerror(errno) ); - return 0; - } - - /* Hmmm: file_filter may have already been removed */ - for( ; a; a = a->chain ) - if( !a->chain && a->filter == file_filter ) { - file_filter_ctx_t *b = a->filter_ov; - FILEP_OR_FD fp = b->fp; - -#if defined(HAVE_DOSISH_SYSTEM) && !defined(FILE_FILTER_USES_STDIO) - ulong size; - static int (* __stdcall get_file_size_ex) - (void *handle, LARGE_INTEGER *size); - static int get_file_size_ex_initialized; - - if (!get_file_size_ex_initialized) - { - void *handle; - - handle = dlopen ("kernel32.dll", RTLD_LAZY); - if (handle) - { - get_file_size_ex = dlsym (handle, "GetFileSizeEx"); - if (!get_file_size_ex) - dlclose (handle); - } - get_file_size_ex_initialized = 1; - } - - if (get_file_size_ex) - { - /* This is a newer system with GetFileSizeEx; we use - this then becuase it seem that GetFileSize won't - return a proper error in case a file is larger than - 4GB. */ - LARGE_INTEGER size; - - if (get_file_size_ex (fp, &size)) - { - if (!size.u.HighPart) - return size.u.LowPart; - if (overflow) - *overflow = 1; - return 0; - } - } - else - { - if ((size=GetFileSize (fp, NULL)) != 0xffffffff) - return size; - } - log_error ("GetFileSize for handle %p failed: %s\n", - fp, w32_strerror (0)); -#else - if( !fstat(my_fileno(fp), &st) ) - return st.st_size; - log_error("fstat() failed: %s\n", strerror(errno) ); -#endif - break; - } - - return 0; -} - - -/* Return the file descriptor of the underlying file or -1 if it is - not available. */ -int -iobuf_get_fd (IOBUF a) -{ - if (a->directfp) - return fileno ( (FILE*)a->directfp ); - - for ( ; a; a = a->chain ) - if (!a->chain && a->filter == file_filter) - { - file_filter_ctx_t *b = a->filter_ov; - FILEP_OR_FD fp = b->fp; - - return my_fileno (fp); - } - - return -1; -} - - -/**************** - * Tell the file position, where the next read will take place - */ -off_t -iobuf_tell( IOBUF a ) -{ - return a->ntotal + a->nbytes; -} - - -#if !defined(HAVE_FSEEKO) && !defined(fseeko) - -#ifdef HAVE_LIMITS_H -# include <limits.h> -#endif -#ifndef LONG_MAX -# define LONG_MAX ((long) ((unsigned long) -1 >> 1)) -#endif -#ifndef LONG_MIN -# define LONG_MIN (-1 - LONG_MAX) -#endif - -/**************** - * A substitute for fseeko, for hosts that don't have it. - */ -static int -fseeko( FILE *stream, off_t newpos, int whence ) -{ - while( newpos != (long) newpos ) { - long pos = newpos < 0 ? LONG_MIN : LONG_MAX; - if( fseek( stream, pos, whence ) != 0 ) - return -1; - newpos -= pos; - whence = SEEK_CUR; - } - return fseek( stream, (long)newpos, whence ); -} -#endif - -/**************** - * This is a very limited implementation. It simply discards all internal - * buffering and removes all filters but the first one. - */ -int -iobuf_seek( IOBUF a, off_t newpos ) -{ - file_filter_ctx_t *b = NULL; - - if( a->directfp ) { - FILE *fp = a->directfp; - if( fseeko( fp, newpos, SEEK_SET ) ) { - log_error("can't seek: %s\n", strerror(errno) ); - return -1; - } - clearerr(fp); - } - else { - for( ; a; a = a->chain ) { - if( !a->chain && a->filter == file_filter ) { - b = a->filter_ov; - break; - } - } - if( !a ) - return -1; -#ifdef FILE_FILTER_USES_STDIO - if( fseeko( b->fp, newpos, SEEK_SET ) ) { - log_error("can't fseek: %s\n", strerror(errno) ); - return -1; - } -#else -#ifdef HAVE_DOSISH_SYSTEM - if (SetFilePointer (b->fp, newpos, NULL, FILE_BEGIN) == 0xffffffff ) { - log_error ("SetFilePointer failed on handle %p: %s\n", - b->fp, w32_strerror (0)); - return -1; - } -#else - if ( lseek (b->fp, newpos, SEEK_SET) == (off_t)-1 ) { - log_error("can't lseek: %s\n", strerror(errno) ); - return -1; - } -#endif -#endif - } - a->d.len = 0; /* discard buffer */ - a->d.start = 0; - a->nbytes = 0; - a->nlimit = 0; - a->nofast &= ~1; - a->ntotal = newpos; - a->error = 0; - /* remove filters, but the last */ - if( a->chain ) - log_debug("pop_filter called in iobuf_seek - please report\n"); - while( a->chain ) - pop_filter( a, a->filter, NULL ); - - return 0; -} - - - - - - -/**************** - * Retrieve the real filename - */ -const char * -iobuf_get_real_fname( IOBUF a ) -{ - if( a->real_fname ) - return a->real_fname; - - /* the old solution */ - for( ; a; a = a->chain ) - if( !a->chain && a->filter == file_filter ) { - file_filter_ctx_t *b = a->filter_ov; - return b->print_only_name? NULL : b->fname; - } - - return NULL; -} - - -/**************** - * Retrieve the filename - */ -const char * -iobuf_get_fname( IOBUF a ) -{ - for( ; a; a = a->chain ) - if( !a->chain && a->filter == file_filter ) { - file_filter_ctx_t *b = a->filter_ov; - return b->fname; - } - - return NULL; -} - - -/**************** - * enable partial block mode as described in the OpenPGP draft. - * LEN is the first length byte on read, but ignored on writes. - */ -void -iobuf_set_partial_block_mode( IOBUF a, size_t len ) -{ - block_filter_ctx_t *ctx = xmalloc_clear( sizeof *ctx ); - - assert( a->use == 1 || a->use == 2 ); - ctx->use = a->use; - if( !len ) { - if( a->use == 1 ) - log_debug("pop_filter called in set_partial_block_mode" - " - please report\n"); - pop_filter(a, block_filter, NULL ); - } - else { - ctx->partial = 1; - ctx->size = 0; - ctx->first_c = len; - iobuf_push_filter(a, block_filter, ctx ); - } -} - - -/**************** - * Same as fgets() but if the buffer is too short a larger one will - * be allocated up to some limit *max_length. - * A line is considered a byte stream ending in a LF. - * Returns the length of the line. EOF is indicated by a line of - * length zero. The last LF may be missing due to an EOF. - * is max_length is zero on return, the line has been truncated. - * - * Note: The buffer is allocated with enough space to append a CR,LF,EOL - */ -unsigned -iobuf_read_line( IOBUF a, byte **addr_of_buffer, - unsigned *length_of_buffer, unsigned *max_length ) -{ - int c; - char *buffer = *addr_of_buffer; - unsigned length = *length_of_buffer; - unsigned nbytes = 0; - unsigned maxlen = *max_length; - char *p; - - if( !buffer ) { /* must allocate a new buffer */ - length = 256; - buffer = xmalloc( length ); - *addr_of_buffer = buffer; - *length_of_buffer = length; - } - - length -= 3; /* reserve 3 bytes (cr,lf,eol) */ - p = buffer; - while( (c=iobuf_get(a)) != -1 ) { - if( nbytes == length ) { /* increase the buffer */ - if( length > maxlen ) { /* this is out limit */ - /* skip the rest of the line */ - while( c != '\n' && (c=iobuf_get(a)) != -1 ) - ; - *p++ = '\n'; /* always append a LF (we have reserved space) */ - nbytes++; - *max_length = 0; /* indicate truncation */ - break; - } - length += 3; /* correct for the reserved byte */ - length += length < 1024? 256 : 1024; - buffer = xrealloc( buffer, length ); - *addr_of_buffer = buffer; - *length_of_buffer = length; - length -= 3; /* and reserve again */ - p = buffer + nbytes; - } - *p++ = c; - nbytes++; - if( c == '\n' ) - break; - } - *p = 0; /* make sure the line is a string */ - - return nbytes; -} - -/* This is the non iobuf specific function */ -int -iobuf_translate_file_handle ( int fd, int for_write ) -{ -#ifdef _WIN32 - { - int x; - - if ( fd <= 2 ) - return fd; /* do not do this for error, stdin, stdout, stderr */ - - x = _open_osfhandle ( fd, for_write? 1:0 ); - if (x==-1 ) - log_error ("failed to translate osfhandle %p\n", (void*)fd ); - else { - /*log_info ("_open_osfhandle %p yields %d%s\n", - (void*)fd, x, for_write? " for writing":"" );*/ - fd = x; - } - } -#endif - return fd; -} - -static int -translate_file_handle ( int fd, int for_write ) -{ -#ifdef _WIN32 -#ifdef FILE_FILTER_USES_STDIO - fd = iobuf_translate_file_handle (fd, for_write); -#else - { - int x; - - if ( fd == 0 ) - x = (int)GetStdHandle (STD_INPUT_HANDLE); - else if (fd == 1) - x = (int)GetStdHandle (STD_OUTPUT_HANDLE); - else if (fd == 2) - x = (int)GetStdHandle (STD_ERROR_HANDLE); - else - x = fd; - - if (x == -1) - log_debug ("GetStdHandle(%d) failed: %s\n", - fd, w32_strerror (0)); - - fd = x; - } -#endif -#endif - return fd; -} - - -void -iobuf_skip_rest(IOBUF a, unsigned long n, int partial) -{ - if ( partial ) { - for (;;) { - if (a->nofast || a->d.start >= a->d.len) { - if (iobuf_readbyte (a) == -1) { - break; - } - } else { - unsigned long count = a->d.len - a->d.start; - a->nbytes += count; - a->d.start = a->d.len; - } - } - } else { - unsigned long remaining = n; - while (remaining > 0) { - if (a->nofast || a->d.start >= a->d.len) { - if (iobuf_readbyte (a) == -1) { - break; - } - --remaining; - } else { - unsigned long count = a->d.len - a->d.start; - if (count > remaining) { - count = remaining; - } - a->nbytes += count; - a->d.start += count; - remaining -= count; - } - } - } -} diff --git a/util/isascii.c b/util/isascii.c deleted file mode 100644 index b71febe99..000000000 --- a/util/isascii.c +++ /dev/null @@ -1,30 +0,0 @@ -/* isascii.c - Replacement for isascii. - * Copyright (C) 2002 Free Software Foundation, Inc. - * - * This file is part of GnuPG. - * - * GnuPG is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * GnuPG is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, - * USA. - */ - -#ifdef HAVE_CONFIG_H -#include <config.h> -#endif - -int -isascii (int c) -{ - return (((c) & ~0x7f) == 0); -} diff --git a/util/logger.c b/util/logger.c deleted file mode 100644 index 857436c43..000000000 --- a/util/logger.c +++ /dev/null @@ -1,265 +0,0 @@ -/* logger.c - log functions - * Copyright (C) 1998, 1999 Free Software Foundation, Inc. - * - * This file is part of GnuPG. - * - * GnuPG is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * GnuPG is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, - * USA. - */ - -#include <config.h> -#include <stdio.h> -#include <stdlib.h> -#include <stdarg.h> -#include <string.h> -#include <errno.h> - -#include "util.h" -#include "i18n.h" - -static char pidstring[15]; -static char *pgm_name; -static int errorcount; -static int strict; -static FILE *logfp; - -/**************** - * Set the logfile to use (not yet implemneted) or, if logfile is NULL, - * the Fd where logoutputs should go. - */ -void -log_set_logfile( const char *name, int fd ) -{ - if( name ) - BUG(); - - if( logfp && logfp != stderr && logfp != stdout ) - fclose( logfp ); - if( fd == 1 ) - logfp = stdout; - else if( fd == 2 ) - logfp = stderr; - else - logfp = fdopen( fd, "a" ); - if( !logfp ) { - logfp = stderr; - log_fatal("can't open fd %d for logging: %s\n", fd, strerror(errno)); - } -} - -FILE * -log_stream() -{ - if( !logfp ) - logfp = stderr; - return logfp; -} - - -void -log_set_name( const char *name ) -{ - xfree(pgm_name); - if( name ) - pgm_name = xstrdup(name); - else - pgm_name = NULL; -} - -const char * -log_get_name(void) -{ - return pgm_name? pgm_name : ""; -} - - -void -log_set_pid( int pid ) -{ - if( pid ) - sprintf(pidstring,"[%u]", (unsigned)pid ); - else - *pidstring = 0; -} - -int -log_get_errorcount( int clear) -{ - int n = errorcount; - if( clear ) - errorcount = 0; - return n; -} - -void -log_inc_errorcount() -{ - errorcount++; -} - -int -log_set_strict(int val) -{ - int old=strict; - strict=val; - return old; -} - -void -g10_log_print_prefix(const char *text) -{ - if( !logfp ) - logfp = stderr; - if( pgm_name ) - fprintf(logfp, "%s%s: %s", pgm_name, pidstring, text ); - else - fprintf(logfp, "?%s: %s", pidstring, text ); -#ifdef __riscos__ - fflush( logfp ); -#endif /* __riscos__ */ -} - - -void -g10_log_info( const char *fmt, ... ) -{ - va_list arg_ptr ; - - g10_log_print_prefix(""); - va_start( arg_ptr, fmt ) ; - vfprintf(logfp,fmt,arg_ptr) ; - va_end(arg_ptr); -#ifdef __riscos__ - fflush( logfp ); -#endif /* __riscos__ */ -} - - -void -g10_log_warning( const char *fmt, ... ) -{ - va_list arg_ptr ; - - if(strict) - { - errorcount++; - g10_log_print_prefix(_("ERROR: ")); - } - else - g10_log_print_prefix(_("WARNING: ")); - - va_start( arg_ptr, fmt ) ; - vfprintf(logfp,fmt,arg_ptr) ; - va_end(arg_ptr); -#ifdef __riscos__ - fflush( logfp ); -#endif /* __riscos__ */ -} - - -void -g10_log_error( const char *fmt, ... ) -{ - va_list arg_ptr ; - - g10_log_print_prefix(""); - va_start( arg_ptr, fmt ) ; - vfprintf(logfp,fmt,arg_ptr) ; - va_end(arg_ptr); - errorcount++; -#ifdef __riscos__ - fflush( logfp ); -#endif /* __riscos__ */ -} - - -void -g10_log_fatal( const char *fmt, ... ) -{ - va_list arg_ptr ; - - g10_log_print_prefix("fatal: "); - va_start( arg_ptr, fmt ) ; - vfprintf(logfp,fmt,arg_ptr) ; - va_end(arg_ptr); - secmem_dump_stats(); -#ifdef __riscos__ - fflush( logfp ); -#endif /* __riscos__ */ - exit(2); -} - -void -g10_log_bug( const char *fmt, ... ) -{ - va_list arg_ptr ; - - putc('\n', stderr ); - g10_log_print_prefix("Ohhhh jeeee: "); - va_start( arg_ptr, fmt ) ; - vfprintf(stderr,fmt,arg_ptr) ; - va_end(arg_ptr); - fflush(stderr); - secmem_dump_stats(); - abort(); -} - -#if defined (__riscos__) \ - || ( __GNUC__ > 2 || (__GNUC__ == 2 && __GNUC_MINOR__ >= 5 )) -void -g10_log_bug0( const char *file, int line, const char *func ) -{ - log_bug(_("... this is a bug (%s:%d:%s)\n"), file, line, func ); -} -#else -void -g10_log_bug0( const char *file, int line ) -{ - log_bug(_("you found a bug ... (%s:%d)\n"), file, line); -} -#endif - -void -g10_log_debug( const char *fmt, ... ) -{ - va_list arg_ptr ; - - g10_log_print_prefix("DBG: "); - va_start( arg_ptr, fmt ) ; - vfprintf(logfp,fmt,arg_ptr) ; - va_end(arg_ptr); -#ifdef __riscos__ - fflush( logfp ); -#endif /* __riscos__ */ -} - - - -void -g10_log_hexdump( const char *text, const char *buf, size_t len ) -{ - int i; - - g10_log_print_prefix(text); - for(i=0; i < len; i++ ) - fprintf(logfp, " %02X", ((const byte*)buf)[i] ); - fputc('\n', logfp); -#ifdef __riscos__ - fflush( logfp ); -#endif /* __riscos__ */ -} - - - diff --git a/util/membuf.c b/util/membuf.c deleted file mode 100644 index 44347fa1b..000000000 --- a/util/membuf.c +++ /dev/null @@ -1,84 +0,0 @@ -/* membuf.c - A simple implementation of a dynamic buffer - * Copyright (C) 2001, 2003 Free Software Foundation, Inc. - * - * This file is part of GnuPG. - * - * GnuPG is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * GnuPG is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, - * USA. - */ - -#include <config.h> -#include <stdlib.h> -#include <errno.h> -#include <string.h> - -#include "util.h" - - -/* A simple implementation of a dynamic buffer. Use init_membuf() to - create a buffer, put_membuf to append bytes and get_membuf to - release and return the buffer. Allocation errors are detected but - only returned at the final get_membuf(), this helps not to clutter - the code with out of core checks. */ - -void -init_membuf (membuf_t *mb, int initiallen) -{ - mb->len = 0; - mb->size = initiallen; - mb->out_of_core = 0; - mb->buf = xmalloc (initiallen); - if (!mb->buf) - mb->out_of_core = errno; -} - - -void -put_membuf (membuf_t *mb, const void *buf, size_t len) -{ - if (mb->out_of_core) - return; - - if (mb->len + len >= mb->size) - { - char *p; - - mb->size += len + 1024; - p = xrealloc (mb->buf, mb->size); - mb->buf = p; - } - memcpy (mb->buf + mb->len, buf, len); - mb->len += len; -} - - -void * -get_membuf (membuf_t *mb, size_t *len) -{ - char *p; - - if (mb->out_of_core) - { - xfree (mb->buf); - mb->buf = NULL; - return NULL; - } - - p = mb->buf; - *len = mb->len; - mb->buf = NULL; - mb->out_of_core = ENOMEM; /* hack to make sure it won't get reused. */ - return p; -} diff --git a/util/memory.c b/util/memory.c deleted file mode 100644 index e16c3d8f7..000000000 --- a/util/memory.c +++ /dev/null @@ -1,647 +0,0 @@ -/* memory.c - memory allocation - * Copyright (C) 1998, 1999, 2001, 2005 Free Software Foundation, Inc. - * - * This file is part of GnuPG. - * - * GnuPG is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * GnuPG is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, - * USA. - * - * - * We use our own memory allocation functions instead of plain malloc(), - * so that we can provide some special enhancements: - * a) functions to provide memory from a secure memory. - * b) by looking at the requested allocation size we - * can reuse memory very quickly (e.g. MPI storage) - * (really needed?) - * c) memory usage reporting if compiled with M_DEBUG - * d) memory checking if compiled with M_GUARD - */ - -#include <config.h> -#include <stdio.h> -#include <stdlib.h> -#include <string.h> -#include <stdarg.h> - -#include "types.h" -#include "memory.h" -#include "util.h" - - -#define MAGIC_NOR_BYTE 0x55 -#define MAGIC_SEC_BYTE 0xcc -#define MAGIC_END_BYTE 0xaa - -/* This is a very crude alignment check which does not work on all CPUs - * IIRC, I once introduced it for testing on an Alpha. We should better - * replace this guard stuff with one provided by a modern malloc library - */ -#if SIZEOF_UNSIGNED_LONG == 8 -#define EXTRA_ALIGN 4 -#else -#define EXTRA_ALIGN 0 -#endif - -#if defined(M_DEBUG) || defined(M_GUARD) - static void membug( const char *fmt, ... ); -#endif - -#ifdef M_DEBUG - -#ifndef M_GUARD -#define M_GUARD 1 -#endif -#undef xmalloc -#undef xmalloc_clear -#undef xmalloc_secure -#undef xmalloc_secure_clear -#undef xrealloc -#undef xfree -#undef m_check -#undef xstrdup -#define FNAME(a) m_debug_ ##a -#define FNAMEX(a) m_debug_ ##a -#define FNAMEXM(a) m_debug_ ##a -#define FNAMEPRT , const char *info -#define FNAMEARG , info -#ifndef __riscos__ -#define store_len(p,n,m) do { add_entry(p,n,m, \ - info, __FUNCTION__); } while(0) -#else -#define store_len(p,n,m) do { add_entry(p,n,m, \ - info, __func__ ); } while(0) -#endif -#else -#define FNAME(a) m_ ##a -#define FNAMEX(a) x ##a -#define FNAMEXM(a) xm ##a -#define FNAMEPRT -#define FNAMEARG -#define store_len(p,n,m) do { ((byte*)p)[EXTRA_ALIGN+0] = n; \ - ((byte*)p)[EXTRA_ALIGN+1] = n >> 8 ; \ - ((byte*)p)[EXTRA_ALIGN+2] = n >> 16 ; \ - ((byte*)p)[EXTRA_ALIGN+3] = m? MAGIC_SEC_BYTE \ - : MAGIC_NOR_BYTE; \ - } while(0) -#endif - - -#ifdef M_GUARD -static long used_memory; -#endif - -#ifdef M_DEBUG /* stuff used for memory debuging */ - -struct info_entry { - struct info_entry *next; - unsigned count; /* call count */ - const char *info; /* the reference to the info string */ -}; - -struct memtbl_entry { - const void *user_p; /* for reference: the pointer given to the user */ - size_t user_n; /* length requested by the user */ - struct memtbl_entry *next; /* to build a list of unused entries */ - const struct info_entry *info; /* points into the table with */ - /* the info strings */ - unsigned inuse:1; /* this entry is in use */ - unsigned count:31; -}; - - -#define INFO_BUCKETS 53 -#define info_hash(p) ( *(u32*)((p)) % INFO_BUCKETS ) -static struct info_entry *info_strings[INFO_BUCKETS]; /* hash table */ - -static struct memtbl_entry *memtbl; /* the table with the memory info */ -static unsigned memtbl_size; /* number of allocated entries */ -static unsigned memtbl_len; /* number of used entries */ -static struct memtbl_entry *memtbl_unused;/* to keep track of unused entries */ - -static void dump_table_at_exit(void); -static void dump_table(void); -static void check_allmem( const char *info ); - -/**************** - * Put the new P into the debug table and return a pointer to the table entry. - * mode is true for security. BY is the name of the function which called us. - */ -static void -add_entry( byte *p, unsigned n, int mode, const char *info, const char *by ) -{ - unsigned index; - struct memtbl_entry *e; - struct info_entry *ie; - - if( memtbl_len < memtbl_size ) - index = memtbl_len++; - else { - struct memtbl_entry *e; - /* look for a used entry in the table. We take the first one, - * so that freed entries remain as long as possible in the table - * (free appends a new one) - */ - if( (e = memtbl_unused) ) { - index = e - memtbl; - memtbl_unused = e->next; - e->next = NULL; - } - else { /* no free entries in the table: extend the table */ - if( !memtbl_size ) { /* first time */ - memtbl_size = 100; - if( !(memtbl = calloc( memtbl_size, sizeof *memtbl )) ) - membug("memory debug table malloc failed\n"); - index = 0; - memtbl_len = 1; - atexit( dump_table_at_exit ); - } - else { /* realloc */ - unsigned n = memtbl_size / 4; /* enlarge by 25% */ - if(!(memtbl = realloc(memtbl, (memtbl_size+n)*sizeof *memtbl))) - membug("memory debug table realloc failed\n"); - memset(memtbl+memtbl_size, 0, n*sizeof *memtbl ); - memtbl_size += n; - index = memtbl_len++; - } - } - } - e = memtbl+index; - if( e->inuse ) - membug("Ooops: entry %u is flagged as in use\n", index); - e->user_p = p + EXTRA_ALIGN + 4; - e->user_n = n; - e->count++; - if( e->next ) - membug("Ooops: entry is in free entry list\n"); - /* do we already have this info string */ - for( ie = info_strings[info_hash(info)]; ie; ie = ie->next ) - if( ie->info == info ) - break; - if( !ie ) { /* no: make a new entry */ - if( !(ie = malloc( sizeof *ie )) ) - membug("can't allocate info entry\n"); - ie->next = info_strings[info_hash(info)]; - info_strings[info_hash(info)] = ie; - ie->info = info; - ie->count = 0; - } - ie->count++; - e->info = ie; - e->inuse = 1; - - /* put the index at the start of the memory */ - p[EXTRA_ALIGN+0] = index; - p[EXTRA_ALIGN+1] = index >> 8 ; - p[EXTRA_ALIGN+2] = index >> 16 ; - p[EXTRA_ALIGN+3] = mode? MAGIC_SEC_BYTE : MAGIC_NOR_BYTE ; - if( DBG_MEMORY ) - log_debug( "%s allocates %u bytes using %s\n", info, e->user_n, by ); -} - - - -/**************** - * Check that the memory block is correct. The magic byte has already been - * checked. Checks which are done here: - * - see whether the index points into our memory table - * - see whether P is the same as the one stored in the table - * - see whether we have already freed this block. - */ -struct memtbl_entry * -check_mem( const byte *p, const char *info ) -{ - unsigned n; - struct memtbl_entry *e; - - n = p[EXTRA_ALIGN+0]; - n |= p[EXTRA_ALIGN+1] << 8; - n |= p[EXTRA_ALIGN+2] << 16; - - if( n >= memtbl_len ) - membug("memory at %p corrupted: index=%u table_len=%u (%s)\n", - p+EXTRA_ALIGN+4, n, memtbl_len, info ); - e = memtbl+n; - - if( e->user_p != p+EXTRA_ALIGN+4 ) - membug("memory at %p corrupted: reference mismatch (%s)\n", - p+EXTRA_ALIGN+4, info ); - if( !e->inuse ) - membug("memory at %p corrupted: marked as free (%s)\n", - p+EXTRA_ALIGN+4, info ); - - if( !(p[EXTRA_ALIGN+3] == MAGIC_NOR_BYTE - || p[EXTRA_ALIGN+3] == MAGIC_SEC_BYTE) ) - membug("memory at %p corrupted: underflow=%02x (%s)\n", - p+EXTRA_ALIGN+4, p[EXTRA_ALIGN+3], info ); - if( p[EXTRA_ALIGN+4+e->user_n] != MAGIC_END_BYTE ) - membug("memory at %p corrupted: overflow=%02x (%s)\n", - p+EXTRA_ALIGN+4, p[EXTRA_ALIGN+4+e->user_n], info ); - return e; -} - - -/**************** - * free the entry and the memory (replaces free) - */ -static void -free_entry( byte *p, const char *info ) -{ - struct memtbl_entry *e, *e2; - - check_allmem("add_entry"); - - e = check_mem(p, info); - if( DBG_MEMORY ) - log_debug( "%s frees %u bytes alloced by %s\n", - info, e->user_n, e->info->info ); - if( !e->inuse ) { - if( e->user_p == p + EXTRA_ALIGN+ 4 ) - membug("freeing an already freed pointer at %p\n", p+EXTRA_ALIGN+4 ); - else - membug("freeing pointer %p which is flagged as freed\n", p+EXTRA_ALIGN+4 ); - } - - e->inuse = 0; - e->next = NULL; - if( !memtbl_unused ) - memtbl_unused = e; - else { - for(e2=memtbl_unused; e2->next; e2 = e2->next ) - ; - e2->next = e; - } - if( m_is_secure(p+EXTRA_ALIGN+4) ) - secmem_free(p); - else { - memset(p,'f', e->user_n+5); - free(p); - } -} - -static void -dump_entry(struct memtbl_entry *e ) -{ - unsigned n = e - memtbl; - - fprintf(stderr, "mem %4u%c %5u %p %5u %s (%u)\n", - n, e->inuse?'a':'u', e->count, e->user_p, e->user_n, - e->info->info, e->info->count ); - - -} - - -static void -dump_table_at_exit( void) -{ - if( DBG_MEMSTAT ) - dump_table(); -} - -static void -dump_table( void) -{ - unsigned n; - struct memtbl_entry *e; - ulong sum = 0, chunks =0; - - for( e = memtbl, n = 0; n < memtbl_len; n++, e++ ) { - if(e->inuse) { - dump_entry(e); - sum += e->user_n; - chunks++; - } - } - fprintf(stderr, " memory used: %8lu bytes in %ld chunks\n", - sum, chunks ); -} - - -static void -check_allmem( const char *info ) -{ - unsigned n; - struct memtbl_entry *e; - - for( e = memtbl, n = 0; n < memtbl_len; n++, e++ ) { - if( e->inuse ) { -#ifndef __riscos__ - check_mem(e->user_p-4-EXTRA_ALIGN, info); -#else - check_mem((const byte *) e->user_p-4-EXTRA_ALIGN, info); -#endif - } - } -} - -#endif /* M_DEBUG */ - -#if defined(M_DEBUG) || defined(M_GUARD) -static void -membug( const char *fmt, ... ) -{ - va_list arg_ptr ; - - fprintf(stderr, "\nMemory Error: " ) ; - va_start( arg_ptr, fmt ) ; - vfprintf(stderr,fmt,arg_ptr) ; - va_end(arg_ptr); - fflush(stderr); -#ifdef M_DEBUG - if( DBG_MEMSTAT ) - dump_table(); -#endif - abort(); -} -#endif - -void -m_print_stats( const char *prefix ) -{ -#ifdef M_DEBUG - unsigned n; - struct memtbl_entry *e; - ulong sum = 0, chunks =0; - - for( e = memtbl, n = 0; n < memtbl_len; n++, e++ ) { - if(e->inuse) { - sum += e->user_n; - chunks++; - } - } - - log_debug( "%s%smemstat: %8lu bytes in %ld chunks used\n", - prefix? prefix:"", prefix? ": ":"", sum, chunks ); -#elif defined(M_GUARD) - log_debug( "%s%smemstat: %8ld bytes\n", - prefix? prefix:"", prefix? ": ":"", used_memory ); -#endif -} - -void -m_dump_table( const char *prefix ) -{ -#ifdef M_DEBUG - fprintf(stderr,"Memory-Table-Dump: %s\n", prefix); - dump_table(); -#endif - m_print_stats( prefix ); -} - - -static void -out_of_core(size_t n, int secure) -{ - log_error ("out of %s memory while allocating %u bytes\n", - secure? "secure":"" ,(unsigned)n ); - if (secure) { - /*secmem_dump_stats ();*/ - log_info ("(this may be caused by too many secret keys used " - "simultaneously or due to excessive large key sizes)\n"); - } -#if defined(M_GUARD) && defined(__riscos__) - abort(); -#endif - exit (2); -} - -/**************** - * Allocate memory of size n. - * This function gives up if we do not have enough memory - */ -void * -FNAMEXM(alloc)( size_t n FNAMEPRT ) -{ - char *p; - -#ifdef M_GUARD - if(!n) - out_of_core(n,0); /* should never happen */ - if( !(p = malloc( n + EXTRA_ALIGN+5 )) ) - out_of_core(n,0); - store_len(p,n,0); - used_memory += n; - p[4+EXTRA_ALIGN+n] = MAGIC_END_BYTE; - return p+EXTRA_ALIGN+4; -#else - /* mallocing zero bytes is undefined by ISO-C, so we better make - sure that it won't happen */ - if (!n) - n = 1; - if( !(p = malloc( n )) ) - out_of_core(n,0); - return p; -#endif -} - -/**************** - * Allocate memory of size n from the secure memory pool. - * This function gives up if we do not have enough memory - */ -void * -FNAMEXM(alloc_secure)( size_t n FNAMEPRT ) -{ - char *p; - -#ifdef M_GUARD - if(!n) - out_of_core(n,1); /* should never happen */ - if( !(p = secmem_malloc( n +EXTRA_ALIGN+ 5 )) ) - out_of_core(n,1); - store_len(p,n,1); - p[4+EXTRA_ALIGN+n] = MAGIC_END_BYTE; - return p+EXTRA_ALIGN+4; -#else - /* mallocing zero bytes is undefined by ISO-C, so we better make - sure that it won't happen */ - if (!n) - n = 1; - if( !(p = secmem_malloc( n )) ) - out_of_core(n,1); - return p; -#endif -} - -void * -FNAMEXM(alloc_clear)( size_t n FNAMEPRT ) -{ - void *p; - p = FNAMEXM(alloc)( n FNAMEARG ); - memset(p, 0, n ); - return p; -} - -void * -FNAMEXM(alloc_secure_clear)( size_t n FNAMEPRT) -{ - void *p; - p = FNAMEXM(alloc_secure)( n FNAMEARG ); - memset(p, 0, n ); - return p; -} - - -/**************** - * realloc and clear the old space - */ -void * -FNAMEX(realloc)( void *a, size_t n FNAMEPRT ) -{ - void *b; - -#ifdef M_GUARD - if( a ) { -#error "--enable-m-guard does not currently work" - unsigned char *p = a; - size_t len = m_size(a); - - if( len >= n ) /* we don't shrink for now */ - return a; - if( p[-1] == MAGIC_SEC_BYTE ) - b = FNAME(alloc_secure_clear)(n FNAMEARG); - else - b = FNAME(alloc_clear)(n FNAMEARG); - FNAME(check)(NULL FNAMEARG); - memcpy(b, a, len ); - FNAME(free)(p FNAMEARG); - } - else - b = FNAME(alloc)(n FNAMEARG); -#else - if( m_is_secure(a) ) { - if( !(b = secmexrealloc( a, n )) ) - out_of_core(n,1); - } - else { - if( !(b = realloc( a, n )) ) - out_of_core(n,0); - } -#endif - - return b; -} - - - -/**************** - * Free a pointer - */ -void -FNAMEX(free)( void *a FNAMEPRT ) -{ - byte *p = a; - - if( !p ) - return; -#ifdef M_DEBUG - free_entry(p-EXTRA_ALIGN-4, info); -#elif defined M_GUARD - m_check(p); - if( m_is_secure(a) ) - secmem_free(p-EXTRA_ALIGN-4); - else { - used_memory -= m_size(a); - free(p-EXTRA_ALIGN-4); - } -#else - if( m_is_secure(a) ) - secmem_free(p); - else - free(p); -#endif -} - - -void -FNAME(check)( const void *a FNAMEPRT ) -{ -#ifdef M_GUARD - const byte *p = a; - -#ifdef M_DEBUG - if( p ) - check_mem(p-EXTRA_ALIGN-4, info); - else - check_allmem(info); -#else - if( !p ) - return; - if( !(p[-1] == MAGIC_NOR_BYTE || p[-1] == MAGIC_SEC_BYTE) ) - membug("memory at %p corrupted (underflow=%02x)\n", p, p[-1] ); - else if( p[m_size(p)] != MAGIC_END_BYTE ) - membug("memory at %p corrupted (overflow=%02x)\n", p, p[-1] ); -#endif -#endif -} - - -size_t -m_size( const void *a ) -{ -#ifndef M_GUARD - log_debug("dummy m_size called\n"); - return 0; -#else - const byte *p = a; - size_t n; - -#ifdef M_DEBUG - n = check_mem(p-EXTRA_ALIGN-4, "m_size")->user_n; -#else - n = ((byte*)p)[-4]; - n |= ((byte*)p)[-3] << 8; - n |= ((byte*)p)[-2] << 16; -#endif - return n; -#endif -} - - -char * -FNAMEX(strdup)( const char *a FNAMEPRT ) -{ - size_t n = strlen(a); - char *p = FNAMEXM(alloc)(n+1 FNAMEARG); - strcpy(p, a); - return p; -} - - -/* Wrapper around xmalloc_clear to take the usual 2 arguments of a - calloc style function. */ -void * -xcalloc (size_t n, size_t m) -{ - size_t nbytes; - - nbytes = n * m; - if (m && nbytes / m != n) - out_of_core (nbytes, 0); - return xmalloc_clear (nbytes); -} - -/* Wrapper around xmalloc_csecure_lear to take the usual 2 arguments - of a calloc style function. */ -void * -xcalloc_secure (size_t n, size_t m) -{ - size_t nbytes; - - nbytes = n * m; - if (m && nbytes / m != n) - out_of_core (nbytes, 1); - return xmalloc_secure_clear (nbytes); -} - diff --git a/util/memrchr.c b/util/memrchr.c deleted file mode 100644 index 5621f7323..000000000 --- a/util/memrchr.c +++ /dev/null @@ -1,49 +0,0 @@ -/* memrchr.c - libc replacement function - * Copyright (C) 2005 Free Software Foundation, Inc. - * - * This file is part of GnuPG. - * - * GnuPG is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * GnuPG is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, - * USA. - */ - -/* - memrchr() is a GNU function that might not be available everywhere. - It's basically the inverse of memchr() - search backwards in a - memory block for a particular character. -*/ - -#include <config.h> -#include <string.h> - -/* There are many ways to optimize this, but this is a simple - unoptimized implementation. */ -void * -memrchr(const void *s, int c, size_t n) -{ - const unsigned char *start=s,*end=s; - - end+=n-1; - - while(end>=start) - { - if(*end==c) - return (void *)end; - else - end--; - } - - return NULL; -} diff --git a/util/miscutil.c b/util/miscutil.c deleted file mode 100644 index 698e80691..000000000 --- a/util/miscutil.c +++ /dev/null @@ -1,480 +0,0 @@ -/* miscutil.c - miscellaneous utilities - * Copyright (C) 1998, 1999, 2000, 2001, 2003, - * 2004, 2005 Free Software Foundation, Inc. - * - * This file is part of GnuPG. - * - * GnuPG is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * GnuPG is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, - * USA. - */ - -#include <config.h> -#include <stdlib.h> -#include <stdio.h> -#include <string.h> -#include <time.h> -#include <ctype.h> -#ifdef HAVE_LANGINFO_H -#include <langinfo.h> -#endif -#include "types.h" -#include "util.h" -#include "i18n.h" - -/**************** - * I know that the OpenPGP protocol has a Y2106 problem ;-) - */ -u32 -make_timestamp() -{ - return time(NULL); -} - -/**************** - * Scan a date string and return a timestamp. - * The only supported format is "yyyy-mm-dd" - * Returns 0 for an invalid date. - */ -u32 -scan_isodatestr( const char *string ) -{ - int year, month, day; - struct tm tmbuf; - time_t stamp; - int i; - - if( strlen(string) != 10 || string[4] != '-' || string[7] != '-' ) - return 0; - for( i=0; i < 4; i++ ) - if( !digitp(string+i) ) - return 0; - if( !digitp(string+5) || !digitp(string+6) ) - return 0; - if( !digitp(string+8) || !digitp(string+9) ) - return 0; - year = atoi(string); - month = atoi(string+5); - day = atoi(string+8); - /* some basic checks */ - if( year < 1970 || month < 1 || month > 12 || day < 1 || day > 31 ) - return 0; - memset( &tmbuf, 0, sizeof tmbuf ); - tmbuf.tm_mday = day; - tmbuf.tm_mon = month-1; - tmbuf.tm_year = year - 1900; - tmbuf.tm_isdst = -1; - stamp = mktime( &tmbuf ); - if( stamp == (time_t)-1 ) - return 0; - return stamp; -} - - -/**************** - * Return a string with a time value in the form: x Y, n D, n H - */ - -const char * -strtimevalue( u32 value ) -{ - static char buffer[30]; - unsigned int years, days, hours, minutes; - - value /= 60; - minutes = value % 60; - value /= 60; - hours = value % 24; - value /= 24; - days = value % 365; - value /= 365; - years = value; - - sprintf(buffer,"%uy%ud%uh%um", years, days, hours, minutes ); - if( years ) - return buffer; - if( days ) - return strchr( buffer, 'y' ) + 1; - return strchr( buffer, 'd' ) + 1; -} - - -/**************** - * Note: this function returns GMT - */ -const char * -strtimestamp( u32 stamp ) -{ - static char buffer[11+5]; - struct tm *tp; - time_t atime = stamp; - - if (atime < 0) { - strcpy (buffer, "????" "-??" "-??"); - } - else { - tp = gmtime( &atime ); - sprintf(buffer,"%04d-%02d-%02d", - 1900+tp->tm_year, tp->tm_mon+1, tp->tm_mday ); - } - return buffer; -} - - -/**************** - * Note: this function returns GMT - */ -const char * -isotimestamp (u32 stamp) -{ - static char buffer[25+5]; - struct tm *tp; - time_t atime = stamp; - - if (atime < 0) { - strcpy (buffer, "????" "-??" "-??" " " "??" ":" "??" ":" "??"); - } - else { - tp = gmtime( &atime ); - sprintf(buffer,"%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); - } - return buffer; -} - -/**************** - * Note: this function returns local time - */ -const char * -asctimestamp( u32 stamp ) -{ - static char buffer[50]; -#if defined (HAVE_STRFTIME) && defined (HAVE_NL_LANGINFO) - static char fmt[50]; -#endif - struct tm *tp; - time_t atime = stamp; - - if (atime < 0) { - strcpy (buffer, "????" "-??" "-??"); - return buffer; - } - - tp = localtime( &atime ); -#ifdef HAVE_STRFTIME -#if defined(HAVE_NL_LANGINFO) - mem2str( fmt, nl_langinfo(D_T_FMT), DIM(fmt)-3 ); - if( strstr( fmt, "%Z" ) == NULL ) - strcat( fmt, " %Z"); - strftime( buffer, DIM(buffer)-1, fmt, tp ); -#else - /* fixme: we should check whether the locale appends a " %Z" - * These locales from glibc don't put the " %Z": - * fi_FI hr_HR ja_JP lt_LT lv_LV POSIX ru_RU ru_SU sv_FI sv_SE zh_CN - */ - strftime( buffer, DIM(buffer)-1, -#ifdef HAVE_W32_SYSTEM - "%c" -#else - "%c %Z" -#endif - , tp ); -#endif - buffer[DIM(buffer)-1] = 0; -#else - mem2str( buffer, asctime(tp), DIM(buffer) ); -#endif - return buffer; -} - - -/**************** - * Print a string to FP, but filter all control characters out. - */ -void -print_string2( FILE *fp, const byte *p, size_t n, int delim, int delim2 ) -{ - for( ; n; n--, p++ ) - if( *p < 0x20 || (*p >= 0x7f && *p < 0xa0) - || *p == delim || *p == delim2 - || ((delim || delim2) && *p=='\\')) - { - putc('\\', fp); - if( *p == '\n' ) - putc('n', fp); - else if( *p == '\r' ) - putc('r', fp); - else if( *p == '\f' ) - putc('f', fp); - else if( *p == '\v' ) - putc('v', fp); - else if( *p == '\b' ) - putc('b', fp); - else if( !*p ) - putc('0', fp); - else - fprintf(fp, "x%02x", *p ); - } - else - putc(*p, fp); -} - -void -print_string( FILE *fp, const byte *p, size_t n, int delim ) -{ - print_string2(fp,p,n,delim,0); -} - -/**************** - * Print an UTF8 string to FP and filter all control characters out. - */ -void -print_utf8_string2 ( FILE *fp, const byte *p, size_t n, int delim ) -{ - size_t i; - char *buf; - - /* we can handle plain ascii simpler, so check for it first */ - for(i=0; i < n; i++ ) { - if( p[i] & 0x80 ) - break; - } - if( i < n ) { - buf = utf8_to_native ( p, n, delim ); - /*(utf8 conversion already does the control character quoting)*/ - fputs( buf, fp ); - xfree( buf ); - } - else - print_string( fp, p, n, delim ); -} - -void -print_utf8_string( FILE *fp, const byte *p, size_t n ) -{ - print_utf8_string2 (fp, p, n, 0); -} - -/**************** - * This function returns a string which is suitable for printing - * Caller must release it with xfree() - */ -char * -make_printable_string( const byte *p, size_t n, int delim ) -{ - size_t save_n, buflen; - const byte *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 < 0xa0) || *p == delim || - (delim && *p=='\\')) { - if( *p=='\n' || *p=='\r' || *p=='\f' - || *p=='\v' || *p=='\b' || !*p ) - buflen += 2; - else - buflen += 4; - } - else - buflen++; - } - p = save_p; - n = save_n; - /* and now make the string */ - d = buffer = xmalloc( buflen ); - for( ; n; n--, p++ ) { - if( *p < 0x20 || (*p >= 0x7f && *p < 0xa0) || *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; -} - -int -answer_is_yes_no_default( const char *s, int def_answer ) -{ - /* TRANSLATORS: See doc/TRANSLATE about this string. */ - const char *long_yes = _("yes"); - const char *short_yes = _("yY"); - /* TRANSLATORS: See doc/TRANSLATE about this string. */ - const char *long_no = _("no"); - const char *short_no = _("nN"); - - /* Note: we have to use the local dependent strcasecmp here */ - if( match_multistr(long_yes,s) ) - return 1; - if( *s && strchr( short_yes, *s ) && !s[1] ) - return 1; - /* test for no strings to catch ambiguities for the next test */ - if( match_multistr(long_no,s) ) - return 0; - if( *s && strchr( short_no, *s ) && !s[1] ) - return 0; - /* test for the english version (for those who are used to type yes) */ - if( !ascii_strcasecmp(s, "yes" ) ) - return 1; - if( *s && strchr( "yY", *s ) && !s[1] ) - return 1; - return def_answer; -} - -int -answer_is_yes( const char *s ) -{ - return answer_is_yes_no_default(s,0); -} - -/**************** - * Return 1 for yes, -1 for quit, or 0 for no - */ -int -answer_is_yes_no_quit( const char *s ) -{ - /* TRANSLATORS: See doc/TRANSLATE about this string. */ - const char *long_yes = _("yes"); - /* TRANSLATORS: See doc/TRANSLATE about this string. */ - const char *long_no = _("no"); - /* TRANSLATORS: See doc/TRANSLATE about this string. */ - const char *long_quit = _("quit"); - const char *short_yes = _("yY"); - const char *short_no = _("nN"); - const char *short_quit = _("qQ"); - - if( match_multistr(long_no,s) ) - return 0; - if( match_multistr(long_yes,s) ) - return 1; - if( match_multistr(long_quit,s) ) - return -1; - if( *s && strchr( short_no, *s ) && !s[1] ) - return 0; - if( *s && strchr( short_yes, *s ) && !s[1] ) - return 1; - if( *s && strchr( short_quit, *s ) && !s[1] ) - return -1; - /* but not here */ - if( !ascii_strcasecmp(s, "yes" ) ) - return 1; - if( !ascii_strcasecmp(s, "quit" ) ) - return -1; - if( *s && strchr( "yY", *s ) && !s[1] ) - return 1; - if( *s && strchr( "qQ", *s ) && !s[1] ) - return -1; - return 0; -} - -/* - Return 1 for okay, 0 for for cancel or DEF_ANSWER for default. - */ -int -answer_is_okay_cancel (const char *s, int def_answer) -{ - /* TRANSLATORS: See doc/TRANSLATE about this string. */ - const char *long_okay = _("okay|okay"); - /* TRANSLATORS: See doc/TRANSLATE about this string. */ - const char *long_cancel = _("cancel|cancel"); - const char *short_okay = _("oO"); - const char *short_cancel = _("cC"); - - /* Note: We have to use the locale dependent strcasecmp */ - if ( match_multistr(long_okay,s) ) - return 1; - if ( match_multistr(long_cancel,s) ) - return 0; - if ( *s && strchr( short_okay, *s ) && !s[1] ) - return 1; - if ( *s && strchr( short_cancel, *s ) && !s[1] ) - return 0; - /* Always test for the English values (not locale here) */ - if ( !ascii_strcasecmp(s, "okay" ) ) - return 1; - if ( !ascii_strcasecmp(s, "ok" ) ) - return 1; - if ( !ascii_strcasecmp(s, "cancel" ) ) - return 0; - if ( *s && strchr( "oO", *s ) && !s[1] ) - return 1; - if ( *s && strchr( "cC", *s ) && !s[1] ) - return 0; - return def_answer; -} - -/* Try match against each substring of multistr, delimited by | */ -int -match_multistr(const char *multistr,const char *match) -{ - do - { - size_t seglen=strcspn(multistr,"|"); - if(!seglen) - break; - /* Using the localized strncasecmp */ - if(strncasecmp(multistr,match,seglen)==0) - return 1; - multistr+=seglen; - if(*multistr=='|') - multistr++; - } - while(*multistr); - - return 0; -} - -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; -} diff --git a/util/mkdtemp.c b/util/mkdtemp.c deleted file mode 100644 index c0ee0bbdb..000000000 --- a/util/mkdtemp.c +++ /dev/null @@ -1,99 +0,0 @@ -/* mkdtemp.c - libc replacement function - * Copyright (C) 2001 Free Software Foundation, Inc. - * - * This file is part of GnuPG. - * - * GnuPG is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * GnuPG is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, - * USA. - */ - -/* This is a replacement function for mkdtemp in case the platform - we're building on (like mine!) doesn't have it. */ - -#include <config.h> -#include <string.h> -#include <errno.h> -#include <sys/stat.h> -#include <sys/types.h> -#include <fcntl.h> -#include <unistd.h> -#include "types.h" -#include "cipher.h" - -#ifdef MKDIR_TAKES_ONE_ARG -# undef mkdir -# define mkdir(a,b) mkdir(a) -#endif - -char *mkdtemp(char *template) -{ - unsigned int attempts,idx,count=0; - char *ch; - - idx=strlen(template); - - /* Walk backwards to count all the Xes */ - while(idx>0 && template[idx-1]=='X') - { - count++; - idx--; - } - - if(count==0) - { - errno=EINVAL; - return NULL; - } - - ch=&template[idx]; - - /* Try 4 times to make the temp directory */ - for(attempts=0;attempts<4;attempts++) - { - unsigned int remaining=count; - char *marker=ch; - byte *randombits; - - idx=0; - - /* Using really random bits is probably overkill here. The - worst thing that can happen with a directory name collision - is that the function will return an error. */ - - randombits=get_random_bits(4*remaining,0,0); - - while(remaining>1) - { - sprintf(marker,"%02X",randombits[idx++]); - marker+=2; - remaining-=2; - } - - /* Any leftover Xes? get_random_bits rounds up to full bytes, - so this is safe. */ - if(remaining>0) - sprintf(marker,"%X",randombits[idx]&0xF); - - xfree(randombits); - - if(mkdir(template,0700)==0) - break; - } - - if(attempts==4) - return NULL; /* keeps the errno from mkdir, whatever it is */ - - return template; -} diff --git a/util/pka.c b/util/pka.c deleted file mode 100644 index 3c9e5c437..000000000 --- a/util/pka.c +++ /dev/null @@ -1,254 +0,0 @@ -/* pka.c - DNS Public Key Association RR access - * Copyright (C) 2005 Free Software Foundation, Inc. - * - * This file is part of GnuPG. - * - * GnuPG is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * GnuPG is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, - * USA. - */ - -#include <config.h> - -#include <stdio.h> -#include <stdlib.h> -#include <string.h> - -#ifdef USE_DNS_PKA -#include <sys/types.h> -#ifdef _WIN32 -#include <windows.h> -#else -#include <netinet/in.h> -#include <arpa/nameser.h> -#include <resolv.h> -#endif -#endif /* USE_DNS_PKA */ - -#include "memory.h" -#include "types.h" -#include "util.h" - - -#ifdef USE_DNS_PKA -/* Parse the TXT resource record. Format is: - - v=pka1;fpr=a4d94e92b0986ab5ee9dcd755de249965b0358a2;uri=string - - For simplicity white spaces are not allowed. Because we expect to - use a new RRTYPE for this in the future we define the TXT really - strict for simplicity: No white spaces, case sensitivity of the - names, order must be as given above. Only URI is optional. - - This function modifies BUFFER. On success 0 is returned, the 20 - byte fingerprint stored at FPR and BUFFER contains the URI or an - empty string. -*/ -static int -parse_txt_record (char *buffer, unsigned char *fpr) -{ - char *p, *pend; - int i; - - p = buffer; - pend = strchr (p, ';'); - if (!pend) - return -1; - *pend++ = 0; - if (strcmp (p, "v=pka1")) - return -1; /* Wrong or missing version. */ - - p = pend; - pend = strchr (p, ';'); - if (pend) - *pend++ = 0; - if (strncmp (p, "fpr=", 4)) - return -1; /* Missing fingerprint part. */ - p += 4; - for (i=0; i < 20 && hexdigitp (p) && hexdigitp (p+1); i++, p += 2) - fpr[i] = xtoi_2 (p); - if (i != 20) - return -1; /* Fingerprint consists not of exactly 40 hexbytes. */ - - p = pend; - if (!p || !*p) - { - *buffer = 0; - return 0; /* Success (no URI given). */ - } - if (strncmp (p, "uri=", 4)) - return -1; /* Unknown part. */ - p += 4; - /* There is an URI, copy it to the start of the buffer. */ - while (*p) - *buffer++ = *p++; - *buffer = 0; - return 0; -} - - -/* For the given email ADDRESS lookup the PKA information in the DNS. - - On success the 20 byte SHA-1 fingerprint is stored at FPR and the - URI will be returned in an allocated buffer. Note that the URI - might be an zero length string as this information is optiobnal. - Caller must xfree the returned string. - - On error NULL is returned and the 20 bytes at FPR are not - defined. */ -char * -get_pka_info (const char *address, unsigned char *fpr) -{ - unsigned char answer[PACKETSZ]; - int anslen; - int qdcount, ancount, nscount, arcount; - int rc; - unsigned char *p, *pend; - const char *domain; - char *name; - - - domain = strrchr (address, '@'); - if (!domain || domain == address || !domain[1]) - return NULL; /* invalid mail address given. */ - - name = malloc (strlen (address) + 5 + 1); - memcpy (name, address, domain - address); - strcpy (stpcpy (name + (domain-address), "._pka."), domain+1); - - anslen = res_query (name, C_IN, T_TXT, answer, PACKETSZ); - xfree (name); - if (anslen < sizeof(HEADER)) - return NULL; /* DNS resolver returned a too short answer. */ - if ( (rc=((HEADER*)answer)->rcode) != NOERROR ) - return NULL; /* DNS resolver returned an error. */ - - /* We assume that PACKETSZ is large enough and don't do dynmically - expansion of the buffer. */ - if (anslen > PACKETSZ) - return NULL; /* DNS resolver returned a too long answer */ - - qdcount = ntohs (((HEADER*)answer)->qdcount); - ancount = ntohs (((HEADER*)answer)->ancount); - nscount = ntohs (((HEADER*)answer)->nscount); - arcount = ntohs (((HEADER*)answer)->arcount); - - if (!ancount) - return NULL; /* Got no answer. */ - - p = answer + sizeof (HEADER); - pend = answer + anslen; /* Actually points directly behind the buffer. */ - - while (qdcount-- && p < pend) - { - rc = dn_skipname (p, pend); - if (rc == -1) - return NULL; - p += rc + QFIXEDSZ; - } - - if (ancount > 1) - return NULL; /* more than one possible gpg trustdns record - none used. */ - - while (ancount-- && p <= pend) - { - unsigned int type, class, txtlen, n; - char *buffer, *bufp; - - rc = dn_skipname (p, pend); - if (rc == -1) - return NULL; - p += rc; - if (p >= pend - 10) - return NULL; /* RR too short. */ - - type = *p++ << 8; - type |= *p++; - class = *p++ << 8; - class |= *p++; - p += 4; - txtlen = *p++ << 8; - txtlen |= *p++; - if (type != T_TXT || class != C_IN) - return NULL; /* Answer does not match the query. */ - - buffer = bufp = xmalloc (txtlen + 1); - while (txtlen && p < pend) - { - for (n = *p++, txtlen--; txtlen && n && p < pend; txtlen--, n--) - *bufp++ = *p++; - } - *bufp = 0; - if (parse_txt_record (buffer, fpr)) - { - xfree (buffer); - return NULL; /* Not a valid gpg trustdns RR. */ - } - return buffer; - } - - return NULL; -} -#else /* !USE_DNS_PKA */ - -/* Dummy version of the function if we can't use the resolver - functions. */ -char * -get_pka_info (const char *address, unsigned char *fpr) -{ - return NULL; -} -#endif /* !USE_DNS_PKA */ - - -#ifdef TEST -int -main(int argc,char *argv[]) -{ - unsigned char fpr[20]; - char *uri; - int i; - - if (argc < 2) - { - fprintf (stderr, "usage: pka mail-addresses\n"); - return 1; - } - argc--; - argv++; - - for (; argc; argc--, argv++) - { - uri = get_pka_info ( *argv, fpr ); - printf ("%s", *argv); - if (uri) - { - putchar (' '); - for (i=0; i < 20; i++) - printf ("%02X", fpr[i]); - if (*uri) - printf (" %s", uri); - xfree (uri); - } - putchar ('\n'); - } - return 0; -} -#endif /* TEST */ - -/* -Local Variables: -compile-command: "cc -DUSE_DNS_PKA -DTEST -I.. -I../include -Wall -g -o pka pka.c -lresolv libutil.a" -End: -*/ diff --git a/util/regcomp.c b/util/regcomp.c deleted file mode 100644 index 766339945..000000000 --- a/util/regcomp.c +++ /dev/null @@ -1,3495 +0,0 @@ -/* Extended regular expression matching and search library. - Copyright (C) 2002 Free Software Foundation, Inc. - This file is part of the GNU C Library. - Contributed by Isamu Hasegawa <[email protected]>. - - The GNU C Library 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. - - The GNU C Library 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 the GNU C Library; if not, write to the Free - Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA - 02110-1301 USA. */ - -#include <assert.h> -#include <ctype.h> -#include <limits.h> -#include <locale.h> -#include <stdio.h> -#include <stdlib.h> -#include <string.h> - -#if defined(_WIN32) && !defined (MB_CUR_MAX) -#define MB_CUR_MAX 2 -#endif - -#if defined HAVE_WCHAR_H || defined _LIBC -# include <wchar.h> -#endif /* HAVE_WCHAR_H || _LIBC */ -#if defined HAVE_WCTYPE_H || defined _LIBC -# include <wctype.h> -#endif /* HAVE_WCTYPE_H || _LIBC */ - -/* In case that the system doesn't have isblank(). */ -#if !defined _LIBC && !defined HAVE_ISBLANK && !defined isblank -# define isblank(ch) ((ch) == ' ' || (ch) == '\t') -#endif - -#ifdef _LIBC -# ifndef _RE_DEFINE_LOCALE_FUNCTIONS -# define _RE_DEFINE_LOCALE_FUNCTIONS 1 -# include <locale/localeinfo.h> -# include <locale/elem-hash.h> -# include <locale/coll-lookup.h> -# endif -#endif - -/* This is for other GNU distributions with internationalized messages. */ -#if HAVE_LIBINTL_H || defined _LIBC -# include <libintl.h> -# ifdef _LIBC -# undef gettext -# define gettext(msgid) \ - INTUSE(__dcgettext) (INTUSE(_libc_intl_domainname), msgid, LC_MESSAGES) -# endif -#else -# define gettext(msgid) (msgid) -#endif - -#ifndef gettext_noop -/* This define is so xgettext can find the internationalizable - strings. */ -# define gettext_noop(String) String -#endif - -#include "_regex.h" /* gnupg */ -#include "regex_internal.h" - -static reg_errcode_t re_compile_internal (regex_t *preg, const char * pattern, - int length, reg_syntax_t syntax); -static void re_compile_fastmap_iter (regex_t *bufp, - const re_dfastate_t *init_state, - char *fastmap); -static reg_errcode_t init_dfa (re_dfa_t *dfa, int pat_len); -static reg_errcode_t init_word_char (re_dfa_t *dfa); -#ifdef RE_ENABLE_I18N -static void free_charset (re_charset_t *cset); -#endif /* RE_ENABLE_I18N */ -static void free_workarea_compile (regex_t *preg); -static reg_errcode_t create_initial_state (re_dfa_t *dfa); -static reg_errcode_t analyze (re_dfa_t *dfa); -static reg_errcode_t analyze_tree (re_dfa_t *dfa, bin_tree_t *node); -static void calc_first (re_dfa_t *dfa, bin_tree_t *node); -static void calc_next (re_dfa_t *dfa, bin_tree_t *node); -static void calc_epsdest (re_dfa_t *dfa, bin_tree_t *node); -static reg_errcode_t duplicate_node (int *new_idx, re_dfa_t *dfa, int org_idx, - unsigned int constraint); -static reg_errcode_t calc_eclosure (re_dfa_t *dfa); -static reg_errcode_t calc_eclosure_iter (re_node_set *new_set, re_dfa_t *dfa, - int node, int root); -static void calc_inveclosure (re_dfa_t *dfa); -static int fetch_number (re_string_t *input, re_token_t *token, - reg_syntax_t syntax); -static re_token_t fetch_token (re_string_t *input, reg_syntax_t syntax); -static int peek_token (re_token_t *token, re_string_t *input, - reg_syntax_t syntax); -static int peek_token_bracket (re_token_t *token, re_string_t *input, - reg_syntax_t syntax); -static bin_tree_t *parse (re_string_t *regexp, regex_t *preg, - reg_syntax_t syntax, reg_errcode_t *err); -static bin_tree_t *parse_reg_exp (re_string_t *regexp, regex_t *preg, - re_token_t *token, reg_syntax_t syntax, - int nest, reg_errcode_t *err); -static bin_tree_t *parse_branch (re_string_t *regexp, regex_t *preg, - re_token_t *token, reg_syntax_t syntax, - int nest, reg_errcode_t *err); -static bin_tree_t *parse_expression (re_string_t *regexp, regex_t *preg, - re_token_t *token, reg_syntax_t syntax, - int nest, reg_errcode_t *err); -static bin_tree_t *parse_sub_exp (re_string_t *regexp, regex_t *preg, - re_token_t *token, reg_syntax_t syntax, - int nest, reg_errcode_t *err); -static bin_tree_t *parse_dup_op (bin_tree_t *dup_elem, re_string_t *regexp, - re_dfa_t *dfa, re_token_t *token, - reg_syntax_t syntax, reg_errcode_t *err); -static bin_tree_t *parse_bracket_exp (re_string_t *regexp, re_dfa_t *dfa, - re_token_t *token, reg_syntax_t syntax, - reg_errcode_t *err); -static reg_errcode_t parse_bracket_element (bracket_elem_t *elem, - re_string_t *regexp, - re_token_t *token, int token_len, - re_dfa_t *dfa, - reg_syntax_t syntax); -static reg_errcode_t parse_bracket_symbol (bracket_elem_t *elem, - re_string_t *regexp, - re_token_t *token); -#ifndef _LIBC -# ifdef RE_ENABLE_I18N -static reg_errcode_t build_range_exp (re_bitset_ptr_t sbcset, - re_charset_t *mbcset, int *range_alloc, - bracket_elem_t *start_elem, - bracket_elem_t *end_elem); -static reg_errcode_t build_collating_symbol (re_bitset_ptr_t sbcset, - re_charset_t *mbcset, - int *coll_syxmalloc, - const unsigned char *name); -# else /* not RE_ENABLE_I18N */ -static reg_errcode_t build_range_exp (re_bitset_ptr_t sbcset, - bracket_elem_t *start_elem, - bracket_elem_t *end_elem); -static reg_errcode_t build_collating_symbol (re_bitset_ptr_t sbcset, - const unsigned char *name); -# endif /* not RE_ENABLE_I18N */ -#endif /* not _LIBC */ -#ifdef RE_ENABLE_I18N -static reg_errcode_t build_equiv_class (re_bitset_ptr_t sbcset, - re_charset_t *mbcset, - int *equiv_class_alloc, - const unsigned char *name); -static reg_errcode_t build_charclass (re_bitset_ptr_t sbcset, - re_charset_t *mbcset, - int *char_class_alloc, - const unsigned char *class_name, - reg_syntax_t syntax); -#else /* not RE_ENABLE_I18N */ -static reg_errcode_t build_equiv_class (re_bitset_ptr_t sbcset, - const unsigned char *name); -static reg_errcode_t build_charclass (re_bitset_ptr_t sbcset, - const unsigned char *class_name, - reg_syntax_t syntax); -#endif /* not RE_ENABLE_I18N */ -static bin_tree_t *build_word_op (re_dfa_t *dfa, int not, reg_errcode_t *err); -static void free_bin_tree (bin_tree_t *tree); -static bin_tree_t *create_tree (bin_tree_t *left, bin_tree_t *right, - re_token_type_t type, int index); -static bin_tree_t *duplicate_tree (const bin_tree_t *src, re_dfa_t *dfa); - -/* This table gives an error message for each of the error codes listed - in regex.h. Obviously the order here has to be same as there. - POSIX doesn't require that we do anything for REG_NOERROR, - but why not be nice? */ - -const char __re_error_msgid[] attribute_hidden = - { -#define REG_NOERROR_IDX 0 - gettext_noop ("Success") /* REG_NOERROR */ - "\0" -#define REG_NOMATCH_IDX (REG_NOERROR_IDX + sizeof "Success") - gettext_noop ("No match") /* REG_NOMATCH */ - "\0" -#define REG_BADPAT_IDX (REG_NOMATCH_IDX + sizeof "No match") - gettext_noop ("Invalid regular expression") /* REG_BADPAT */ - "\0" -#define REG_ECOLLATE_IDX (REG_BADPAT_IDX + sizeof "Invalid regular expression") - gettext_noop ("Invalid collation character") /* REG_ECOLLATE */ - "\0" -#define REG_ECTYPE_IDX (REG_ECOLLATE_IDX + sizeof "Invalid collation character") - gettext_noop ("Invalid character class name") /* REG_ECTYPE */ - "\0" -#define REG_EESCAPE_IDX (REG_ECTYPE_IDX + sizeof "Invalid character class name") - gettext_noop ("Trailing backslash") /* REG_EESCAPE */ - "\0" -#define REG_ESUBREG_IDX (REG_EESCAPE_IDX + sizeof "Trailing backslash") - gettext_noop ("Invalid back reference") /* REG_ESUBREG */ - "\0" -#define REG_EBRACK_IDX (REG_ESUBREG_IDX + sizeof "Invalid back reference") - gettext_noop ("Unmatched [ or [^") /* REG_EBRACK */ - "\0" -#define REG_EPAREN_IDX (REG_EBRACK_IDX + sizeof "Unmatched [ or [^") - gettext_noop ("Unmatched ( or \\(") /* REG_EPAREN */ - "\0" -#define REG_EBRACE_IDX (REG_EPAREN_IDX + sizeof "Unmatched ( or \\(") - gettext_noop ("Unmatched \\{") /* REG_EBRACE */ - "\0" -#define REG_BADBR_IDX (REG_EBRACE_IDX + sizeof "Unmatched \\{") - gettext_noop ("Invalid content of \\{\\}") /* REG_BADBR */ - "\0" -#define REG_ERANGE_IDX (REG_BADBR_IDX + sizeof "Invalid content of \\{\\}") - gettext_noop ("Invalid range end") /* REG_ERANGE */ - "\0" -#define REG_ESPACE_IDX (REG_ERANGE_IDX + sizeof "Invalid range end") - gettext_noop ("Memory exhausted") /* REG_ESPACE */ - "\0" -#define REG_BADRPT_IDX (REG_ESPACE_IDX + sizeof "Memory exhausted") - gettext_noop ("Invalid preceding regular expression") /* REG_BADRPT */ - "\0" -#define REG_EEND_IDX (REG_BADRPT_IDX + sizeof "Invalid preceding regular expression") - gettext_noop ("Premature end of regular expression") /* REG_EEND */ - "\0" -#define REG_ESIZE_IDX (REG_EEND_IDX + sizeof "Premature end of regular expression") - gettext_noop ("Regular expression too big") /* REG_ESIZE */ - "\0" -#define REG_ERPAREN_IDX (REG_ESIZE_IDX + sizeof "Regular expression too big") - gettext_noop ("Unmatched ) or \\)") /* REG_ERPAREN */ - }; - -const size_t __re_error_msgid_idx[] attribute_hidden = - { - REG_NOERROR_IDX, - REG_NOMATCH_IDX, - REG_BADPAT_IDX, - REG_ECOLLATE_IDX, - REG_ECTYPE_IDX, - REG_EESCAPE_IDX, - REG_ESUBREG_IDX, - REG_EBRACK_IDX, - REG_EPAREN_IDX, - REG_EBRACE_IDX, - REG_BADBR_IDX, - REG_ERANGE_IDX, - REG_ESPACE_IDX, - REG_BADRPT_IDX, - REG_EEND_IDX, - REG_ESIZE_IDX, - REG_ERPAREN_IDX - }; - -/* Entry points for GNU code. */ - -/* re_compile_pattern is the GNU regular expression compiler: it - compiles PATTERN (of length LENGTH) and puts the result in BUFP. - Returns 0 if the pattern was valid, otherwise an error string. - - Assumes the `allocated' (and perhaps `buffer') and `translate' fields - are set in BUFP on entry. */ - -const char * -re_compile_pattern (pattern, length, bufp) - const char *pattern; - size_t length; - struct re_pattern_buffer *bufp; -{ - reg_errcode_t ret; - - /* GNU code is written to assume at least RE_NREGS registers will be set - (and at least one extra will be -1). */ - bufp->regs_allocated = REGS_UNALLOCATED; - - /* And GNU code determines whether or not to get register information - by passing null for the REGS argument to re_match, etc., not by - setting no_sub. */ - bufp->no_sub = 0; - - /* Match anchors at newline. */ - bufp->newline_anchor = 1; - - ret = re_compile_internal (bufp, pattern, length, re_syntax_options); - - if (!ret) - return NULL; - return gettext (__re_error_msgid + __re_error_msgid_idx[(int) ret]); -} -#ifdef _LIBC -weak_alias (__re_compile_pattern, re_compile_pattern) -#endif - -/* Set by `re_set_syntax' to the current regexp syntax to recognize. Can - also be assigned to arbitrarily: each pattern buffer stores its own - syntax, so it can be changed between regex compilations. */ -/* This has no initializer because initialized variables in Emacs - become read-only after dumping. */ -reg_syntax_t re_syntax_options; - - -/* Specify the precise syntax of regexps for compilation. This provides - for compatibility for various utilities which historically have - different, incompatible syntaxes. - - The argument SYNTAX is a bit mask comprised of the various bits - defined in regex.h. We return the old syntax. */ - -reg_syntax_t -re_set_syntax (syntax) - reg_syntax_t syntax; -{ - reg_syntax_t ret = re_syntax_options; - - re_syntax_options = syntax; - return ret; -} -#ifdef _LIBC -weak_alias (__re_set_syntax, re_set_syntax) -#endif - -int -re_compile_fastmap (bufp) - struct re_pattern_buffer *bufp; -{ - re_dfa_t *dfa = (re_dfa_t *) bufp->buffer; - char *fastmap = bufp->fastmap; - - memset (fastmap, '\0', sizeof (char) * SBC_MAX); - re_compile_fastmap_iter (bufp, dfa->init_state, fastmap); - if (dfa->init_state != dfa->init_state_word) - re_compile_fastmap_iter (bufp, dfa->init_state_word, fastmap); - if (dfa->init_state != dfa->init_state_nl) - re_compile_fastmap_iter (bufp, dfa->init_state_nl, fastmap); - if (dfa->init_state != dfa->init_state_begbuf) - re_compile_fastmap_iter (bufp, dfa->init_state_begbuf, fastmap); - bufp->fastmap_accurate = 1; - return 0; -} -#ifdef _LIBC -weak_alias (__re_compile_fastmap, re_compile_fastmap) -#endif - -/* Helper function for re_compile_fastmap. - Compile fastmap for the initial_state INIT_STATE. */ - -static void -re_compile_fastmap_iter (bufp, init_state, fastmap) - regex_t *bufp; - const re_dfastate_t *init_state; - char *fastmap; -{ - re_dfa_t *dfa = (re_dfa_t *) bufp->buffer; - int node_cnt; - for (node_cnt = 0; node_cnt < init_state->nodes.nelem; ++node_cnt) - { - int node = init_state->nodes.elems[node_cnt]; - re_token_type_t type = dfa->nodes[node].type; - if (type == OP_CONTEXT_NODE) - { - node = dfa->nodes[node].opr.ctx_info->entity; - type = dfa->nodes[node].type; - } - - if (type == CHARACTER) - fastmap[dfa->nodes[node].opr.c] = 1; - else if (type == SIMPLE_BRACKET) - { - int i, j, ch; - for (i = 0, ch = 0; i < BITSET_UINTS; ++i) - for (j = 0; j < UINT_BITS; ++j, ++ch) - if (dfa->nodes[node].opr.sbcset[i] & (1 << j)) - fastmap[ch] = 1; - } -#ifdef RE_ENABLE_I18N - else if (type == COMPLEX_BRACKET) - { - int i; - re_charset_t *cset = dfa->nodes[node].opr.mbcset; - if (cset->non_match || cset->ncoll_syms || cset->nequiv_classes - || cset->nranges || cset->nchar_classes) - { -# ifdef _LIBC - if (_NL_CURRENT_WORD (LC_COLLATE, _NL_COLLATE_NRULES) != 0) - { - /* In this case we want to catch the bytes which are - the first byte of any collation elements. - e.g. In da_DK, we want to catch 'a' since "aa" - is a valid collation element, and don't catch - 'b' since 'b' is the only collation element - which starts from 'b'. */ - int j, ch; - const int32_t *table = (const int32_t *) - _NL_CURRENT (LC_COLLATE, _NL_COLLATE_TABLEMB); - for (i = 0, ch = 0; i < BITSET_UINTS; ++i) - for (j = 0; j < UINT_BITS; ++j, ++ch) - if (table[ch] < 0) - fastmap[ch] = 1; - } -# else - if (MB_CUR_MAX > 1) - for (i = 0; i < SBC_MAX; ++i) - if (__btowc (i) == WEOF) - fastmap[i] = 1; -# endif /* not _LIBC */ - } - for (i = 0; i < cset->nmbchars; ++i) - { - char buf[256]; - wctomb (buf, cset->mbchars[i]); - fastmap[*(unsigned char *) buf] = 1; - } - } -#endif /* RE_ENABLE_I18N */ - else if (type == END_OF_RE || type == OP_PERIOD -#ifdef RE_ENABLE_I18N - || type == COMPLEX_BRACKET -#endif /* RE_ENABLE_I18N */ - ) - { - memset (fastmap, '\1', sizeof (char) * SBC_MAX); - if (type == END_OF_RE) - bufp->can_be_null = 1; - return; - } - } -} - -/* Entry point for POSIX code. */ -/* regcomp takes a regular expression as a string and compiles it. - - PREG is a regex_t *. We do not expect any fields to be initialized, - since POSIX says we shouldn't. Thus, we set - - `buffer' to the compiled pattern; - `used' to the length of the compiled pattern; - `syntax' to RE_SYNTAX_POSIX_EXTENDED if the - REG_EXTENDED bit in CFLAGS is set; otherwise, to - RE_SYNTAX_POSIX_BASIC; - `newline_anchor' to REG_NEWLINE being set in CFLAGS; - `fastmap' to an allocated space for the fastmap; - `fastmap_accurate' to zero; - `re_nsub' to the number of subexpressions in PATTERN. - - PATTERN is the address of the pattern string. - - CFLAGS is a series of bits which affect compilation. - - If REG_EXTENDED is set, we use POSIX extended syntax; otherwise, we - use POSIX basic syntax. - - If REG_NEWLINE is set, then . and [^...] don't match newline. - Also, regexec will try a match beginning after every newline. - - If REG_ICASE is set, then we considers upper- and lowercase - versions of letters to be equivalent when matching. - - If REG_NOSUB is set, then when PREG is passed to regexec, that - routine will report only success or failure, and nothing about the - registers. - - It returns 0 if it succeeds, nonzero if it doesn't. (See regex.h for - the return codes and their meanings.) */ - -int -regcomp (preg, pattern, cflags) - regex_t *__restrict preg; - const char *__restrict pattern; - int cflags; -{ - reg_errcode_t ret; - reg_syntax_t syntax = ((cflags & REG_EXTENDED) ? RE_SYNTAX_POSIX_EXTENDED - : RE_SYNTAX_POSIX_BASIC); - - preg->buffer = NULL; - preg->allocated = 0; - preg->used = 0; - - /* Try to allocate space for the fastmap. */ - preg->fastmap = re_malloc (char, SBC_MAX); - if (BE (preg->fastmap == NULL, 0)) - return REG_ESPACE; - - syntax |= (cflags & REG_ICASE) ? RE_ICASE : 0; - - /* If REG_NEWLINE is set, newlines are treated differently. */ - if (cflags & REG_NEWLINE) - { /* REG_NEWLINE implies neither . nor [^...] match newline. */ - syntax &= ~RE_DOT_NEWLINE; - syntax |= RE_HAT_LISTS_NOT_NEWLINE; - /* It also changes the matching behavior. */ - preg->newline_anchor = 1; - } - else - preg->newline_anchor = 0; - preg->no_sub = !!(cflags & REG_NOSUB); - preg->translate = NULL; - - ret = re_compile_internal (preg, pattern, strlen (pattern), syntax); - - /* POSIX doesn't distinguish between an unmatched open-group and an - unmatched close-group: both are REG_EPAREN. */ - if (ret == REG_ERPAREN) - ret = REG_EPAREN; - - /* We have already checked preg->fastmap != NULL. */ - if (BE (ret == REG_NOERROR, 1)) - { - /* Compute the fastmap now, since regexec cannot modify the pattern - buffer. */ - if (BE (re_compile_fastmap (preg) == -2, 0)) - { - /* Some error occurred while computing the fastmap, just forget - about it. */ - re_free (preg->fastmap); - preg->fastmap = NULL; - } - } - - return (int) ret; -} -#ifdef _LIBC -weak_alias (__regcomp, regcomp) -#endif - -/* Returns a message corresponding to an error code, ERRCODE, returned - from either regcomp or regexec. We don't use PREG here. */ - -size_t -regerror (errcode, preg, errbuf, errbuf_size) - int errcode; - const regex_t *preg; - char *errbuf; - size_t errbuf_size; -{ - const char *msg; - size_t msg_size; - - if (BE (errcode < 0 - || errcode >= (int) (sizeof (__re_error_msgid_idx) - / sizeof (__re_error_msgid_idx[0])), 0)) - /* Only error codes returned by the rest of the code should be passed - to this routine. If we are given anything else, or if other regex - code generates an invalid error code, then the program has a bug. - Dump core so we can fix it. */ - abort (); - - msg = gettext (__re_error_msgid + __re_error_msgid_idx[errcode]); - - msg_size = strlen (msg) + 1; /* Includes the null. */ - - if (BE (errbuf_size != 0, 1)) - { - if (BE (msg_size > errbuf_size, 0)) - { -#if defined HAVE_MEMPCPY || defined _LIBC - *((char *) __mempcpy (errbuf, msg, errbuf_size - 1)) = '\0'; -#else - memcpy (errbuf, msg, errbuf_size - 1); - errbuf[errbuf_size - 1] = 0; -#endif - } - else - memcpy (errbuf, msg, msg_size); - } - - return msg_size; -} -#ifdef _LIBC -weak_alias (__regerror, regerror) -#endif - -/* Free dynamically allocated space used by PREG. */ - -void -regfree (preg) - regex_t *preg; -{ - int i, j; - re_dfa_t *dfa = (re_dfa_t *) preg->buffer; - if (BE (dfa != NULL, 1)) - { - re_free (dfa->subexps); - - for (i = 0; i < dfa->nodes_len; ++i) - { - re_token_t *node = dfa->nodes + i; -#ifdef RE_ENABLE_I18N - if (node->type == COMPLEX_BRACKET && node->duplicated == 0) - free_charset (node->opr.mbcset); - else -#endif /* RE_ENABLE_I18N */ - if (node->type == SIMPLE_BRACKET && node->duplicated == 0) - re_free (node->opr.sbcset); - else if (node->type == OP_CONTEXT_NODE) - { - if (dfa->nodes[node->opr.ctx_info->entity].type == OP_BACK_REF) - { - if (node->opr.ctx_info->bkref_eclosure != NULL) - re_node_set_free (node->opr.ctx_info->bkref_eclosure); - re_free (node->opr.ctx_info->bkref_eclosure); - } - re_free (node->opr.ctx_info); - } - } - re_free (dfa->firsts); - re_free (dfa->nexts); - for (i = 0; i < dfa->nodes_len; ++i) - { - if (dfa->eclosures != NULL) - re_node_set_free (dfa->eclosures + i); - if (dfa->inveclosures != NULL) - re_node_set_free (dfa->inveclosures + i); - if (dfa->edests != NULL) - re_node_set_free (dfa->edests + i); - } - re_free (dfa->edests); - re_free (dfa->eclosures); - re_free (dfa->inveclosures); - re_free (dfa->nodes); - - for (i = 0; i <= dfa->state_hash_mask; ++i) - { - struct re_state_table_entry *entry = dfa->state_table + i; - for (j = 0; j < entry->num; ++j) - { - re_dfastate_t *state = entry->array[j]; - if (state->entrance_nodes != &state->nodes) - { - re_node_set_free (state->entrance_nodes); - re_free (state->entrance_nodes); - } - re_node_set_free (&state->nodes); - re_free (state->trtable); - re_free (state->trtable_search); - re_free (state); - } - re_free (entry->array); - } - re_free (dfa->state_table); - - if (dfa->word_char != NULL) - re_free (dfa->word_char); -#ifdef DEBUG - re_free (dfa->re_str); -#endif - re_free (dfa); - } - re_free (preg->fastmap); -} -#ifdef _LIBC -weak_alias (__regfree, regfree) -#endif - -/* Entry points compatible with 4.2 BSD regex library. We don't define - them unless specifically requested. */ - -#if defined _REGEX_RE_COMP || defined _LIBC - -/* BSD has one and only one pattern buffer. */ -static struct re_pattern_buffer re_comp_buf; - -char * -# ifdef _LIBC -/* Make these definitions weak in libc, so POSIX programs can redefine - these names if they don't use our functions, and still use - regcomp/regexec above without link errors. */ -weak_function -# endif -re_comp (s) - const char *s; -{ - reg_errcode_t ret; - - if (!s) - { - if (!re_comp_buf.buffer) - return gettext ("No previous regular expression"); - return 0; - } - - if (!re_comp_buf.buffer) - { - re_comp_buf.fastmap = (char *) malloc (SBC_MAX); - if (re_comp_buf.fastmap == NULL) - return (char *) gettext (__re_error_msgid - + __re_error_msgid_idx[(int) REG_ESPACE]); - } - - /* Since `re_exec' always passes NULL for the `regs' argument, we - don't need to initialize the pattern buffer fields which affect it. */ - - /* Match anchors at newlines. */ - re_comp_buf.newline_anchor = 1; - - ret = re_compile_internal (&re_comp_buf, s, strlen (s), re_syntax_options); - - if (!ret) - return NULL; - - /* Yes, we're discarding `const' here if !HAVE_LIBINTL. */ - return (char *) gettext (__re_error_msgid + __re_error_msgid_idx[(int) ret]); -} -#endif /* _REGEX_RE_COMP */ - -/* Internal entry point. - Compile the regular expression PATTERN, whose length is LENGTH. - SYNTAX indicate regular expression's syntax. */ - -static reg_errcode_t -re_compile_internal (preg, pattern, length, syntax) - regex_t *preg; - const char * pattern; - int length; - reg_syntax_t syntax; -{ - reg_errcode_t err = REG_NOERROR; - re_dfa_t *dfa; - re_string_t regexp; - - /* Initialize the pattern buffer. */ - preg->fastmap_accurate = 0; - preg->syntax = syntax; - preg->not_bol = preg->not_eol = 0; - preg->used = 0; - preg->re_nsub = 0; - - /* Initialize the dfa. */ - dfa = (re_dfa_t *) preg->buffer; - if (preg->allocated < sizeof (re_dfa_t)) - { - /* If zero allocated, but buffer is non-null, try to realloc - enough space. This loses if buffer's address is bogus, but - that is the user's responsibility. If ->buffer is NULL this - is a simple allocation. */ - dfa = re_realloc (preg->buffer, re_dfa_t, 1); - if (dfa == NULL) - return REG_ESPACE; - preg->allocated = sizeof (re_dfa_t); - } - preg->buffer = (unsigned char *) dfa; - preg->used = sizeof (re_dfa_t); - - err = init_dfa (dfa, length); - if (BE (err != REG_NOERROR, 0)) - { - re_free (dfa); - preg->buffer = NULL; - return err; - } -#ifdef DEBUG - dfa->re_str = re_malloc (char, length + 1); - strncpy (dfa->re_str, pattern, length + 1); -#endif - - err = re_string_construct (®exp, pattern, length, preg->translate, - syntax & RE_ICASE); - if (BE (err != REG_NOERROR, 0)) - { - re_free (dfa); - preg->buffer = NULL; - return err; - } - - /* Parse the regular expression, and build a structure tree. */ - preg->re_nsub = 0; - dfa->str_tree = parse (®exp, preg, syntax, &err); - if (BE (dfa->str_tree == NULL, 0)) - goto re_compile_internal_free_return; - - /* Analyze the tree and collect information which is necessary to - create the dfa. */ - err = analyze (dfa); - if (BE (err != REG_NOERROR, 0)) - goto re_compile_internal_free_return; - - /* Then create the initial state of the dfa. */ - err = create_initial_state (dfa); - if (BE (err != REG_NOERROR, 0)) - goto re_compile_internal_free_return; - - re_compile_internal_free_return: - /* Release work areas. */ - free_workarea_compile (preg); - re_string_destruct (®exp); - - return err; -} - -/* Initialize DFA. We use the length of the regular expression PAT_LEN - as the initial length of some arrays. */ - -static reg_errcode_t -init_dfa (dfa, pat_len) - re_dfa_t *dfa; - int pat_len; -{ - int table_size; - - memset (dfa, '\0', sizeof (re_dfa_t)); - - dfa->nodes_alloc = pat_len + 1; - dfa->nodes = re_malloc (re_token_t, dfa->nodes_alloc); - - dfa->states_alloc = pat_len + 1; - - /* table_size = 2 ^ ceil(log pat_len) */ - for (table_size = 1; table_size > 0; table_size <<= 1) - if (table_size > pat_len) - break; - - dfa->state_table = calloc (sizeof (struct re_state_table_entry), table_size); - dfa->state_hash_mask = table_size - 1; - - dfa->subexps_alloc = 1; - dfa->subexps = re_malloc (re_subexp_t, dfa->subexps_alloc); - dfa->word_char = NULL; - - if (BE (dfa->nodes == NULL || dfa->state_table == NULL - || dfa->subexps == NULL, 0)) - { - /* We don't bother to free anything which was allocated. Very - soon the process will go down anyway. */ - dfa->subexps = NULL; - dfa->state_table = NULL; - dfa->nodes = NULL; - return REG_ESPACE; - } - return REG_NOERROR; -} - -/* Initialize WORD_CHAR table, which indicate which character is - "word". In this case "word" means that it is the word construction - character used by some operators like "\<", "\>", etc. */ - -static reg_errcode_t -init_word_char (dfa) - re_dfa_t *dfa; -{ - int i, j, ch; - dfa->word_char = (re_bitset_ptr_t) calloc (sizeof (bitset), 1); - if (BE (dfa->word_char == NULL, 0)) - return REG_ESPACE; - for (i = 0, ch = 0; i < BITSET_UINTS; ++i) - for (j = 0; j < UINT_BITS; ++j, ++ch) - if (isalnum (ch) || ch == '_') - dfa->word_char[i] |= 1 << j; - return REG_NOERROR; -} - -/* Free the work area which are only used while compiling. */ - -static void -free_workarea_compile (preg) - regex_t *preg; -{ - re_dfa_t *dfa = (re_dfa_t *) preg->buffer; - free_bin_tree (dfa->str_tree); - dfa->str_tree = NULL; -} - -/* Create initial states for all contexts. */ - -static reg_errcode_t -create_initial_state (dfa) - re_dfa_t *dfa; -{ - int first, i; - reg_errcode_t err; - re_node_set init_nodes; - - /* Initial states have the epsilon closure of the node which is - the first node of the regular expression. */ - first = dfa->str_tree->first; - dfa->init_node = first; - err = re_node_set_init_copy (&init_nodes, dfa->eclosures + first); - if (BE (err != REG_NOERROR, 0)) - return err; - - /* The back-references which are in initial states can epsilon transit, - since in this case all of the subexpressions can be null. - Then we add epsilon closures of the nodes which are the next nodes of - the back-references. */ - if (dfa->nbackref > 0) - for (i = 0; i < init_nodes.nelem; ++i) - { - int node_idx = init_nodes.elems[i]; - re_token_type_t type = dfa->nodes[node_idx].type; - - int clexp_idx; - int entity = (type != OP_CONTEXT_NODE ? node_idx - : dfa->nodes[node_idx].opr.ctx_info->entity); - if ((type != OP_CONTEXT_NODE - || (dfa->nodes[entity].type != OP_BACK_REF)) - && (type != OP_BACK_REF)) - continue; - for (clexp_idx = 0; clexp_idx < init_nodes.nelem; ++clexp_idx) - { - re_token_t *clexp_node; - clexp_node = dfa->nodes + init_nodes.elems[clexp_idx]; - if (clexp_node->type == OP_CLOSE_SUBEXP - && clexp_node->opr.idx + 1 == dfa->nodes[entity].opr.idx) - break; - } - if (clexp_idx == init_nodes.nelem) - continue; - - if (type == OP_CONTEXT_NODE - && (dfa->nodes[dfa->nodes[node_idx].opr.ctx_info->entity].type - == OP_BACK_REF)) - { - int prev_nelem = init_nodes.nelem; - re_node_set_merge (&init_nodes, - dfa->nodes[node_idx].opr.ctx_info->bkref_eclosure); - if (prev_nelem < init_nodes.nelem) - i = 0; - } - else if (type == OP_BACK_REF) - { - int next_idx = dfa->nexts[node_idx]; - if (!re_node_set_contains (&init_nodes, next_idx)) - { - re_node_set_merge (&init_nodes, dfa->eclosures + next_idx); - i = 0; - } - } - } - - /* It must be the first time to invoke acquire_state. */ - dfa->init_state = re_acquire_state_context (&err, dfa, &init_nodes, 0); - /* We don't check ERR here, since the initial state must not be NULL. */ - if (BE (dfa->init_state == NULL, 0)) - return err; - if (dfa->init_state->has_constraint) - { - dfa->init_state_word = re_acquire_state_context (&err, dfa, &init_nodes, - CONTEXT_WORD); - dfa->init_state_nl = re_acquire_state_context (&err, dfa, &init_nodes, - CONTEXT_NEWLINE); - dfa->init_state_begbuf = re_acquire_state_context (&err, dfa, - &init_nodes, - CONTEXT_NEWLINE - | CONTEXT_BEGBUF); - if (BE (dfa->init_state_word == NULL || dfa->init_state_nl == NULL - || dfa->init_state_begbuf == NULL, 0)) - return err; - } - else - dfa->init_state_word = dfa->init_state_nl - = dfa->init_state_begbuf = dfa->init_state; - - re_node_set_free (&init_nodes); - return REG_NOERROR; -} - -/* Analyze the structure tree, and calculate "first", "next", "edest", - "eclosure", and "inveclosure". */ - -static reg_errcode_t -analyze (dfa) - re_dfa_t *dfa; -{ - int i; - reg_errcode_t ret; - - /* Allocate arrays. */ - dfa->firsts = re_malloc (int, dfa->nodes_alloc); - dfa->nexts = re_malloc (int, dfa->nodes_alloc); - dfa->edests = re_malloc (re_node_set, dfa->nodes_alloc); - dfa->eclosures = re_malloc (re_node_set, dfa->nodes_alloc); - dfa->inveclosures = re_malloc (re_node_set, dfa->nodes_alloc); - if (BE (dfa->firsts == NULL || dfa->nexts == NULL || dfa->edests == NULL - || dfa->eclosures == NULL || dfa->inveclosures == NULL, 0)) - return REG_ESPACE; - /* Initialize them. */ - for (i = 0; i < dfa->nodes_len; ++i) - { - dfa->firsts[i] = -1; - dfa->nexts[i] = -1; - re_node_set_init_empty (dfa->edests + i); - re_node_set_init_empty (dfa->eclosures + i); - re_node_set_init_empty (dfa->inveclosures + i); - } - - ret = analyze_tree (dfa, dfa->str_tree); - if (BE (ret == REG_NOERROR, 1)) - { - ret = calc_eclosure (dfa); - if (ret == REG_NOERROR) - calc_inveclosure (dfa); - } - return ret; -} - -/* Helper functions for analyze. - This function calculate "first", "next", and "edest" for the subtree - whose root is NODE. */ - -static reg_errcode_t -analyze_tree (dfa, node) - re_dfa_t *dfa; - bin_tree_t *node; -{ - reg_errcode_t ret; - if (node->first == -1) - calc_first (dfa, node); - if (node->next == -1) - calc_next (dfa, node); - if (node->eclosure.nelem == 0) - calc_epsdest (dfa, node); - /* Calculate "first" etc. for the left child. */ - if (node->left != NULL) - { - ret = analyze_tree (dfa, node->left); - if (BE (ret != REG_NOERROR, 0)) - return ret; - } - /* Calculate "first" etc. for the right child. */ - if (node->right != NULL) - { - ret = analyze_tree (dfa, node->right); - if (BE (ret != REG_NOERROR, 0)) - return ret; - } - return REG_NOERROR; -} - -/* Calculate "first" for the node NODE. */ -static void -calc_first (dfa, node) - re_dfa_t *dfa; - bin_tree_t *node; -{ - int idx, type; - idx = node->node_idx; - type = (node->type == 0) ? dfa->nodes[idx].type : node->type; - - switch (type) - { -#ifdef DEBUG - case OP_OPEN_BRACKET: - case OP_CLOSE_BRACKET: - case OP_OPEN_DUP_NUM: - case OP_CLOSE_DUP_NUM: - case OP_NON_MATCH_LIST: - case OP_OPEN_COLL_ELEM: - case OP_CLOSE_COLL_ELEM: - case OP_OPEN_EQUIV_CLASS: - case OP_CLOSE_EQUIV_CLASS: - case OP_OPEN_CHAR_CLASS: - case OP_CLOSE_CHAR_CLASS: - /* These must not be appeared here. */ - assert (0); -#endif - case END_OF_RE: - case CHARACTER: - case OP_PERIOD: - case OP_DUP_ASTERISK: - case OP_DUP_QUESTION: -#ifdef RE_ENABLE_I18N - case COMPLEX_BRACKET: -#endif /* RE_ENABLE_I18N */ - case SIMPLE_BRACKET: - case OP_BACK_REF: - case ANCHOR: - case OP_OPEN_SUBEXP: - case OP_CLOSE_SUBEXP: - node->first = idx; - break; - case OP_DUP_PLUS: -#ifdef DEBUG - assert (node->left != NULL); -#endif - if (node->left->first == -1) - calc_first (dfa, node->left); - node->first = node->left->first; - break; - case OP_ALT: - node->first = idx; - break; - /* else fall through */ - default: -#ifdef DEBUG - assert (node->left != NULL); -#endif - if (node->left->first == -1) - calc_first (dfa, node->left); - node->first = node->left->first; - break; - } - if (node->type == 0) - dfa->firsts[idx] = node->first; -} - -/* Calculate "next" for the node NODE. */ - -static void -calc_next (dfa, node) - re_dfa_t *dfa; - bin_tree_t *node; -{ - int idx, type; - bin_tree_t *parent = node->parent; - if (parent == NULL) - { - node->next = -1; - idx = node->node_idx; - if (node->type == 0) - dfa->nexts[idx] = node->next; - return; - } - - idx = parent->node_idx; - type = (parent->type == 0) ? dfa->nodes[idx].type : parent->type; - - switch (type) - { - case OP_DUP_ASTERISK: - case OP_DUP_PLUS: - node->next = idx; - break; - case CONCAT: - if (parent->left == node) - { - if (parent->right->first == -1) - calc_first (dfa, parent->right); - node->next = parent->right->first; - break; - } - /* else fall through */ - default: - if (parent->next == -1) - calc_next (dfa, parent); - node->next = parent->next; - break; - } - idx = node->node_idx; - if (node->type == 0) - dfa->nexts[idx] = node->next; -} - -/* Calculate "edest" for the node NODE. */ - -static void -calc_epsdest (dfa, node) - re_dfa_t *dfa; - bin_tree_t *node; -{ - int idx; - idx = node->node_idx; - if (node->type == 0) - { - if (dfa->nodes[idx].type == OP_DUP_ASTERISK - || dfa->nodes[idx].type == OP_DUP_PLUS - || dfa->nodes[idx].type == OP_DUP_QUESTION) - { - if (node->left->first == -1) - calc_first (dfa, node->left); - if (node->next == -1) - calc_next (dfa, node); - re_node_set_init_2 (dfa->edests + idx, node->left->first, - node->next); - } - else if (dfa->nodes[idx].type == OP_ALT) - { - int left, right; - if (node->left != NULL) - { - if (node->left->first == -1) - calc_first (dfa, node->left); - left = node->left->first; - } - else - { - if (node->next == -1) - calc_next (dfa, node); - left = node->next; - } - if (node->right != NULL) - { - if (node->right->first == -1) - calc_first (dfa, node->right); - right = node->right->first; - } - else - { - if (node->next == -1) - calc_next (dfa, node); - right = node->next; - } - re_node_set_init_2 (dfa->edests + idx, left, right); - } - else if (dfa->nodes[idx].type == ANCHOR - || dfa->nodes[idx].type == OP_OPEN_SUBEXP - || dfa->nodes[idx].type == OP_CLOSE_SUBEXP) - re_node_set_init_1 (dfa->edests + idx, node->next); - } -} - -/* Duplicate the node whose index is ORG_IDX and set the constraint CONSTRAINT. - The new index will be stored in NEW_IDX and return REG_NOERROR if succeeded, - otherwise return the error code. */ - -static reg_errcode_t -duplicate_node (new_idx, dfa, org_idx, constraint) - re_dfa_t *dfa; - int *new_idx, org_idx; - unsigned int constraint; -{ - re_token_t dup; - int dup_idx; - reg_errcode_t err; - - dup.type = OP_CONTEXT_NODE; - if (dfa->nodes[org_idx].type == OP_CONTEXT_NODE) - { - /* If the node whose index is ORG_IDX is the same as the intended - node, use it. */ - if (dfa->nodes[org_idx].constraint == constraint) - { - *new_idx = org_idx; - return REG_NOERROR; - } - dup.constraint = constraint | - dfa->nodes[org_idx].constraint; - } - else - dup.constraint = constraint; - - /* In case that `entity' points OP_CONTEXT_NODE, - we correct `entity' to real entity in calc_inveclosures(). */ - dup.opr.ctx_info = malloc (sizeof (*dup.opr.ctx_info)); - dup_idx = re_dfa_add_node (dfa, dup, 1); - if (BE (dup.opr.ctx_info == NULL || dup_idx == -1, 0)) - return REG_ESPACE; - dup.opr.ctx_info->entity = org_idx; - dup.opr.ctx_info->bkref_eclosure = NULL; - - dfa->nodes[dup_idx].duplicated = 1; - dfa->firsts[dup_idx] = dfa->firsts[org_idx]; - dfa->nexts[dup_idx] = dfa->nexts[org_idx]; - err = re_node_set_init_copy (dfa->edests + dup_idx, dfa->edests + org_idx); - if (BE (err != REG_NOERROR, 0)) - return err; - /* Since we don't duplicate epsilon nodes, epsilon closure have - only itself. */ - err = re_node_set_init_1 (dfa->eclosures + dup_idx, dup_idx); - if (BE (err != REG_NOERROR, 0)) - return err; - err = re_node_set_init_1 (dfa->inveclosures + dup_idx, dup_idx); - if (BE (err != REG_NOERROR, 0)) - return err; - /* Then we must update inveclosure for this node. - We process them at last part of calc_eclosure(), - since we don't complete to calculate them here. */ - - *new_idx = dup_idx; - return REG_NOERROR; -} - -static void -calc_inveclosure (dfa) - re_dfa_t *dfa; -{ - int src, idx, dest, entity; - for (src = 0; src < dfa->nodes_len; ++src) - { - for (idx = 0; idx < dfa->eclosures[src].nelem; ++idx) - { - dest = dfa->eclosures[src].elems[idx]; - re_node_set_insert (dfa->inveclosures + dest, src); - } - - entity = src; - while (dfa->nodes[entity].type == OP_CONTEXT_NODE) - { - entity = dfa->nodes[entity].opr.ctx_info->entity; - re_node_set_merge (dfa->inveclosures + src, - dfa->inveclosures + entity); - dfa->nodes[src].opr.ctx_info->entity = entity; - } - } -} - -/* Calculate "eclosure" for all the node in DFA. */ - -static reg_errcode_t -calc_eclosure (dfa) - re_dfa_t *dfa; -{ - int idx, node_idx, max, incomplete = 0; -#ifdef DEBUG - assert (dfa->nodes_len > 0); -#endif - /* For each nodes, calculate epsilon closure. */ - for (node_idx = 0, max = dfa->nodes_len; ; ++node_idx) - { - reg_errcode_t err; - re_node_set eclosure_elem; - if (node_idx == max) - { - if (!incomplete) - break; - incomplete = 0; - node_idx = 0; - } - -#ifdef DEBUG - assert (dfa->nodes[node_idx].type != OP_CONTEXT_NODE); - assert (dfa->eclosures[node_idx].nelem != -1); -#endif - /* If we have already calculated, skip it. */ - if (dfa->eclosures[node_idx].nelem != 0) - continue; - /* Calculate epsilon closure of `node_idx'. */ - err = calc_eclosure_iter (&eclosure_elem, dfa, node_idx, 1); - if (BE (err != REG_NOERROR, 0)) - return err; - - if (dfa->eclosures[node_idx].nelem == 0) - { - incomplete = 1; - re_node_set_free (&eclosure_elem); - } - } - - /* for duplicated nodes. */ - for (idx = max; idx < dfa->nodes_len; ++idx) - { - int entity, i, constraint; - re_node_set *bkref_eclosure; - entity = dfa->nodes[idx].opr.ctx_info->entity; - re_node_set_merge (dfa->inveclosures + idx, dfa->inveclosures + entity); - if (dfa->nodes[entity].type != OP_BACK_REF) - continue; - - /* If the node is backreference, duplicate the epsilon closure of - the next node. Since it may epsilon transit. */ - /* Note: duplicate_node() may realloc dfa->eclosures, etc. */ - bkref_eclosure = re_malloc (re_node_set, 1); - if (BE (bkref_eclosure == NULL, 0)) - return REG_ESPACE; - re_node_set_init_empty (bkref_eclosure); - constraint = dfa->nodes[idx].constraint; - for (i = 0; i < dfa->eclosures[dfa->nexts[idx]].nelem; ++i) - { - int dest_node_idx = dfa->eclosures[dfa->nexts[idx]].elems[i]; - if (!IS_EPSILON_NODE (dfa->nodes[dest_node_idx].type)) - { - reg_errcode_t err; - err = duplicate_node (&dest_node_idx, dfa, dest_node_idx, - constraint); - if (BE (err != REG_NOERROR, 0)) - return err; - } - re_node_set_insert (bkref_eclosure, dest_node_idx); - } - dfa->nodes[idx].opr.ctx_info->bkref_eclosure = bkref_eclosure; - } - - return REG_NOERROR; -} - -/* Calculate epsilon closure of NODE. */ - -static reg_errcode_t -calc_eclosure_iter (new_set, dfa, node, root) - re_node_set *new_set; - re_dfa_t *dfa; - int node, root; -{ - reg_errcode_t err; - unsigned int constraint; - int i, max, incomplete = 0; - re_node_set eclosure; - err = re_node_set_alloc (&eclosure, dfa->edests[node].nelem + 1); - if (BE (err != REG_NOERROR, 0)) - return err; - - /* This indicates that we are calculating this node now. - We reference this value to avoid infinite loop. */ - dfa->eclosures[node].nelem = -1; - - constraint = ((dfa->nodes[node].type == ANCHOR) - ? dfa->nodes[node].opr.ctx_type : 0); - - /* Expand each epsilon destination nodes. */ - if (dfa->edests[node].nelem != 0) - for (i = 0; i < dfa->edests[node].nelem; ++i) - { - re_node_set eclosure_elem; - int edest = dfa->edests[node].elems[i]; - /* If calculating the epsilon closure of `edest' is in progress, - return intermediate result. */ - if (dfa->eclosures[edest].nelem == -1) - { - incomplete = 1; - continue; - } - /* If we haven't calculated the epsilon closure of `edest' yet, - calculate now. Otherwise use calculated epsilon closure. */ - if (dfa->eclosures[edest].nelem == 0) - { - err = calc_eclosure_iter (&eclosure_elem, dfa, edest, 0); - if (BE (err != REG_NOERROR, 0)) - return err; - } - else - eclosure_elem = dfa->eclosures[edest]; - /* Merge the epsilon closure of `edest'. */ - re_node_set_merge (&eclosure, &eclosure_elem); - /* If the epsilon closure of `edest' is incomplete, - the epsilon closure of this node is also incomplete. */ - if (dfa->eclosures[edest].nelem == 0) - { - incomplete = 1; - re_node_set_free (&eclosure_elem); - } - } - - /* If the current node has constraints, duplicate all non-epsilon nodes. - Since they must inherit the constraints. */ - if (constraint) - for (i = 0, max = eclosure.nelem; i < max; ++i) - { - int dest = eclosure.elems[i]; - if (!IS_EPSILON_NODE (dfa->nodes[dest].type)) - { - int dup_dest; - reg_errcode_t err; - err = duplicate_node (&dup_dest, dfa, dest, constraint); - if (BE (err != REG_NOERROR, 0)) - return err; - if (dest != dup_dest) - { - re_node_set_remove_at (&eclosure, i--); - re_node_set_insert (&eclosure, dup_dest); - --max; - } - } - } - - /* Epsilon closures include itself. */ - re_node_set_insert (&eclosure, node); - if (incomplete && !root) - dfa->eclosures[node].nelem = 0; - else - dfa->eclosures[node] = eclosure; - *new_set = eclosure; - return REG_NOERROR; -} - -/* Functions for token which are used in the parser. */ - -/* Fetch a token from INPUT. - We must not use this function inside bracket expressions. */ - -static re_token_t -fetch_token (input, syntax) - re_string_t *input; - reg_syntax_t syntax; -{ - re_token_t token; - int consumed_byte; - consumed_byte = peek_token (&token, input, syntax); - re_string_skip_bytes (input, consumed_byte); - return token; -} - -/* Peek a token from INPUT, and return the length of the token. - We must not use this function inside bracket expressions. */ - -static int -peek_token (token, input, syntax) - re_token_t *token; - re_string_t *input; - reg_syntax_t syntax; -{ - unsigned char c; - - if (re_string_eoi (input)) - { - token->type = END_OF_RE; - return 0; - } - - c = re_string_peek_byte (input, 0); - token->opr.c = c; - -#ifdef RE_ENABLE_I18N - token->mb_partial = 0; - if (MB_CUR_MAX > 1 && - !re_string_first_byte (input, re_string_cur_idx (input))) - { - token->type = CHARACTER; - token->mb_partial = 1; - return 1; - } -#endif - if (c == '\\') - { - unsigned char c2; - if (re_string_cur_idx (input) + 1 >= re_string_length (input)) - { - token->type = BACK_SLASH; - return 1; - } - - c2 = re_string_peek_byte_case (input, 1); - token->opr.c = c2; - token->type = CHARACTER; - switch (c2) - { - case '|': - if (!(syntax & RE_LIMITED_OPS) && !(syntax & RE_NO_BK_VBAR)) - token->type = OP_ALT; - break; - case '1': case '2': case '3': case '4': case '5': - case '6': case '7': case '8': case '9': - if (!(syntax & RE_NO_BK_REFS)) - { - token->type = OP_BACK_REF; - token->opr.idx = c2 - '0'; - } - break; - case '<': - if (!(syntax & RE_NO_GNU_OPS)) - { - token->type = ANCHOR; - token->opr.idx = WORD_FIRST; - } - break; - case '>': - if (!(syntax & RE_NO_GNU_OPS)) - { - token->type = ANCHOR; - token->opr.idx = WORD_LAST; - } - break; - case 'b': - if (!(syntax & RE_NO_GNU_OPS)) - { - token->type = ANCHOR; - token->opr.idx = WORD_DELIM; - } - break; - case 'B': - if (!(syntax & RE_NO_GNU_OPS)) - { - token->type = ANCHOR; - token->opr.idx = INSIDE_WORD; - } - break; - case 'w': - if (!(syntax & RE_NO_GNU_OPS)) - token->type = OP_WORD; - break; - case 'W': - if (!(syntax & RE_NO_GNU_OPS)) - token->type = OP_NOTWORD; - break; - case '`': - if (!(syntax & RE_NO_GNU_OPS)) - { - token->type = ANCHOR; - token->opr.idx = BUF_FIRST; - } - break; - case '\'': - if (!(syntax & RE_NO_GNU_OPS)) - { - token->type = ANCHOR; - token->opr.idx = BUF_LAST; - } - break; - case '(': - if (!(syntax & RE_NO_BK_PARENS)) - token->type = OP_OPEN_SUBEXP; - break; - case ')': - if (!(syntax & RE_NO_BK_PARENS)) - token->type = OP_CLOSE_SUBEXP; - break; - case '+': - if (!(syntax & RE_LIMITED_OPS) && (syntax & RE_BK_PLUS_QM)) - token->type = OP_DUP_PLUS; - break; - case '?': - if (!(syntax & RE_LIMITED_OPS) && (syntax & RE_BK_PLUS_QM)) - token->type = OP_DUP_QUESTION; - break; - case '{': - if ((syntax & RE_INTERVALS) && (!(syntax & RE_NO_BK_BRACES))) - token->type = OP_OPEN_DUP_NUM; - break; - case '}': - if ((syntax & RE_INTERVALS) && (!(syntax & RE_NO_BK_BRACES))) - token->type = OP_CLOSE_DUP_NUM; - break; - default: - break; - } - return 2; - } - - token->type = CHARACTER; - switch (c) - { - case '\n': - if (syntax & RE_NEWLINE_ALT) - token->type = OP_ALT; - break; - case '|': - if (!(syntax & RE_LIMITED_OPS) && (syntax & RE_NO_BK_VBAR)) - token->type = OP_ALT; - break; - case '*': - token->type = OP_DUP_ASTERISK; - break; - case '+': - if (!(syntax & RE_LIMITED_OPS) && !(syntax & RE_BK_PLUS_QM)) - token->type = OP_DUP_PLUS; - break; - case '?': - if (!(syntax & RE_LIMITED_OPS) && !(syntax & RE_BK_PLUS_QM)) - token->type = OP_DUP_QUESTION; - break; - case '{': - if ((syntax & RE_INTERVALS) && (syntax & RE_NO_BK_BRACES)) - token->type = OP_OPEN_DUP_NUM; - break; - case '}': - if ((syntax & RE_INTERVALS) && (syntax & RE_NO_BK_BRACES)) - token->type = OP_CLOSE_DUP_NUM; - break; - case '(': - if (syntax & RE_NO_BK_PARENS) - token->type = OP_OPEN_SUBEXP; - break; - case ')': - if (syntax & RE_NO_BK_PARENS) - token->type = OP_CLOSE_SUBEXP; - break; - case '[': - token->type = OP_OPEN_BRACKET; - break; - case '.': - token->type = OP_PERIOD; - break; - case '^': - if (!(syntax & RE_CONTEXT_INDEP_ANCHORS) && - re_string_cur_idx (input) != 0) - { - char prev = re_string_peek_byte (input, -1); - if (prev != '|' && prev != '(' && - (!(syntax & RE_NEWLINE_ALT) || prev != '\n')) - break; - } - token->type = ANCHOR; - token->opr.idx = LINE_FIRST; - break; - case '$': - if (!(syntax & RE_CONTEXT_INDEP_ANCHORS) && - re_string_cur_idx (input) + 1 != re_string_length (input)) - { - re_token_t next; - re_string_skip_bytes (input, 1); - peek_token (&next, input, syntax); - re_string_skip_bytes (input, -1); - if (next.type != OP_ALT && next.type != OP_CLOSE_SUBEXP) - break; - } - token->type = ANCHOR; - token->opr.idx = LINE_LAST; - break; - default: - break; - } - return 1; -} - -/* Peek a token from INPUT, and return the length of the token. - We must not use this function out of bracket expressions. */ - -static int -peek_token_bracket (token, input, syntax) - re_token_t *token; - re_string_t *input; - reg_syntax_t syntax; -{ - unsigned char c; - if (re_string_eoi (input)) - { - token->type = END_OF_RE; - return 0; - } - c = re_string_peek_byte (input, 0); - token->opr.c = c; - -#ifdef RE_ENABLE_I18N - if (MB_CUR_MAX > 1 && - !re_string_first_byte (input, re_string_cur_idx (input))) - { - token->type = CHARACTER; - return 1; - } -#endif /* RE_ENABLE_I18N */ - - if (c == '\\' && (syntax & RE_BACKSLASH_ESCAPE_IN_LISTS)) - { - /* In this case, '\' escape a character. */ - unsigned char c2; - c2 = re_string_peek_byte (input, 1); - token->opr.c = c2; - token->type = CHARACTER; - return 1; - } - if (c == '[') /* '[' is a special char in a bracket exps. */ - { - unsigned char c2; - int token_len; - c2 = re_string_peek_byte (input, 1); - token->opr.c = c2; - token_len = 2; - switch (c2) - { - case '.': - token->type = OP_OPEN_COLL_ELEM; - break; - case '=': - token->type = OP_OPEN_EQUIV_CLASS; - break; - case ':': - if (syntax & RE_CHAR_CLASSES) - { - token->type = OP_OPEN_CHAR_CLASS; - break; - } - /* else fall through. */ - default: - token->type = CHARACTER; - token->opr.c = c; - token_len = 1; - break; - } - return token_len; - } - switch (c) - { - case '-': - token->type = OP_CHARSET_RANGE; - break; - case ']': - token->type = OP_CLOSE_BRACKET; - break; - case '^': - token->type = OP_NON_MATCH_LIST; - break; - default: - token->type = CHARACTER; - } - return 1; -} - -/* Functions for parser. */ - -/* Entry point of the parser. - Parse the regular expression REGEXP and return the structure tree. - If an error is occured, ERR is set by error code, and return NULL. - This function build the following tree, from regular expression <reg_exp>: - CAT - / \ - / \ - <reg_exp> EOR - - CAT means concatenation. - EOR means end of regular expression. */ - -static bin_tree_t * -parse (regexp, preg, syntax, err) - re_string_t *regexp; - regex_t *preg; - reg_syntax_t syntax; - reg_errcode_t *err; -{ - re_dfa_t *dfa = (re_dfa_t *) preg->buffer; - bin_tree_t *tree, *eor, *root; - re_token_t current_token; - int new_idx; - current_token = fetch_token (regexp, syntax); - tree = parse_reg_exp (regexp, preg, ¤t_token, syntax, 0, err); - if (BE (*err != REG_NOERROR && tree == NULL, 0)) - return NULL; - new_idx = re_dfa_add_node (dfa, current_token, 0); - eor = create_tree (NULL, NULL, 0, new_idx); - if (tree != NULL) - root = create_tree (tree, eor, CONCAT, 0); - else - root = eor; - if (BE (new_idx == -1 || eor == NULL || root == NULL, 0)) - return *err = REG_ESPACE, NULL; - return root; -} - -/* This function build the following tree, from regular expression - <branch1>|<branch2>: - ALT - / \ - / \ - <branch1> <branch2> - - ALT means alternative, which represents the operator `|'. */ - -static bin_tree_t * -parse_reg_exp (regexp, preg, token, syntax, nest, err) - re_string_t *regexp; - regex_t *preg; - re_token_t *token; - reg_syntax_t syntax; - int nest; - reg_errcode_t *err; -{ - re_dfa_t *dfa = (re_dfa_t *) preg->buffer; - bin_tree_t *tree, *branch = NULL; - int new_idx; - tree = parse_branch (regexp, preg, token, syntax, nest, err); - if (BE (*err != REG_NOERROR && tree == NULL, 0)) - return NULL; - - while (token->type == OP_ALT) - { - re_token_t alt_token = *token; - new_idx = re_dfa_add_node (dfa, alt_token, 0); - *token = fetch_token (regexp, syntax); - if (token->type != OP_ALT && token->type != END_OF_RE - && (nest == 0 || token->type != OP_CLOSE_SUBEXP)) - { - branch = parse_branch (regexp, preg, token, syntax, nest, err); - if (BE (*err != REG_NOERROR && branch == NULL, 0)) - { - free_bin_tree (tree); - return NULL; - } - } - else - branch = NULL; - tree = create_tree (tree, branch, 0, new_idx); - if (BE (new_idx == -1 || tree == NULL, 0)) - return *err = REG_ESPACE, NULL; - dfa->has_plural_match = 1; - } - return tree; -} - -/* This function build the following tree, from regular expression - <exp1><exp2>: - CAT - / \ - / \ - <exp1> <exp2> - - CAT means concatenation. */ - -static bin_tree_t * -parse_branch (regexp, preg, token, syntax, nest, err) - re_string_t *regexp; - regex_t *preg; - re_token_t *token; - reg_syntax_t syntax; - int nest; - reg_errcode_t *err; -{ - bin_tree_t *tree, *exp; - tree = parse_expression (regexp, preg, token, syntax, nest, err); - if (BE (*err != REG_NOERROR && tree == NULL, 0)) - return NULL; - - while (token->type != OP_ALT && token->type != END_OF_RE - && (nest == 0 || token->type != OP_CLOSE_SUBEXP)) - { - exp = parse_expression (regexp, preg, token, syntax, nest, err); - if (BE (*err != REG_NOERROR && exp == NULL, 0)) - { - free_bin_tree (tree); - return NULL; - } - if (tree != NULL && exp != NULL) - { - tree = create_tree (tree, exp, CONCAT, 0); - if (tree == NULL) - return *err = REG_ESPACE, NULL; - } - else if (tree == NULL) - tree = exp; - /* Otherwise exp == NULL, we don't need to create new tree. */ - } - return tree; -} - -/* This function build the following tree, from regular expression a*: - * - | - a -*/ - -static bin_tree_t * -parse_expression (regexp, preg, token, syntax, nest, err) - re_string_t *regexp; - regex_t *preg; - re_token_t *token; - reg_syntax_t syntax; - int nest; - reg_errcode_t *err; -{ - re_dfa_t *dfa = (re_dfa_t *) preg->buffer; - bin_tree_t *tree; - int new_idx; - switch (token->type) - { - case CHARACTER: - new_idx = re_dfa_add_node (dfa, *token, 0); - tree = create_tree (NULL, NULL, 0, new_idx); - if (BE (new_idx == -1 || tree == NULL, 0)) - return *err = REG_ESPACE, NULL; -#ifdef RE_ENABLE_I18N - if (MB_CUR_MAX > 1) - { - while (!re_string_eoi (regexp) - && !re_string_first_byte (regexp, re_string_cur_idx (regexp))) - { - bin_tree_t *mbc_remain; - *token = fetch_token (regexp, syntax); - new_idx = re_dfa_add_node (dfa, *token, 0); - mbc_remain = create_tree (NULL, NULL, 0, new_idx); - tree = create_tree (tree, mbc_remain, CONCAT, 0); - if (BE (new_idx == -1 || mbc_remain == NULL || tree == NULL, 0)) - return *err = REG_ESPACE, NULL; - } - } -#endif - break; - case OP_OPEN_SUBEXP: - tree = parse_sub_exp (regexp, preg, token, syntax, nest + 1, err); - if (BE (*err != REG_NOERROR && tree == NULL, 0)) - return NULL; - break; - case OP_OPEN_BRACKET: - tree = parse_bracket_exp (regexp, dfa, token, syntax, err); - if (BE (*err != REG_NOERROR && tree == NULL, 0)) - return NULL; - break; - case OP_BACK_REF: - if (BE (preg->re_nsub < token->opr.idx - || dfa->subexps[token->opr.idx - 1].end == -1, 0)) - { - *err = REG_ESUBREG; - return NULL; - } - new_idx = re_dfa_add_node (dfa, *token, 0); - tree = create_tree (NULL, NULL, 0, new_idx); - if (BE (new_idx == -1 || tree == NULL, 0)) - return *err = REG_ESPACE, NULL; - ++dfa->nbackref; - dfa->has_mb_node = 1; - break; - case OP_DUP_ASTERISK: - case OP_DUP_PLUS: - case OP_DUP_QUESTION: - case OP_OPEN_DUP_NUM: - if (syntax & RE_CONTEXT_INVALID_OPS) - return *err = REG_BADRPT, NULL; - else if (syntax & RE_CONTEXT_INDEP_OPS) - { - *token = fetch_token (regexp, syntax); - return parse_expression (regexp, preg, token, syntax, nest, err); - } - /* else fall through */ - case OP_CLOSE_SUBEXP: - if ((token->type == OP_CLOSE_SUBEXP) && - !(syntax & RE_UNMATCHED_RIGHT_PAREN_ORD)) - return *err = REG_ERPAREN, NULL; - /* else fall through */ - case OP_CLOSE_DUP_NUM: - /* We treat it as a normal character. */ - - /* Then we can these characters as normal characters. */ - token->type = CHARACTER; - new_idx = re_dfa_add_node (dfa, *token, 0); - tree = create_tree (NULL, NULL, 0, new_idx); - if (BE (new_idx == -1 || tree == NULL, 0)) - return *err = REG_ESPACE, NULL; - break; - case ANCHOR: - if (dfa->word_char == NULL) - { - *err = init_word_char (dfa); - if (BE (*err != REG_NOERROR, 0)) - return NULL; - } - if (token->opr.ctx_type == WORD_DELIM) - { - bin_tree_t *tree_first, *tree_last; - int idx_first, idx_last; - token->opr.ctx_type = WORD_FIRST; - idx_first = re_dfa_add_node (dfa, *token, 0); - tree_first = create_tree (NULL, NULL, 0, idx_first); - token->opr.ctx_type = WORD_LAST; - idx_last = re_dfa_add_node (dfa, *token, 0); - tree_last = create_tree (NULL, NULL, 0, idx_last); - token->type = OP_ALT; - new_idx = re_dfa_add_node (dfa, *token, 0); - tree = create_tree (tree_first, tree_last, 0, new_idx); - if (BE (idx_first == -1 || idx_last == -1 || new_idx == -1 - || tree_first == NULL || tree_last == NULL - || tree == NULL, 0)) - return *err = REG_ESPACE, NULL; - } - else - { - new_idx = re_dfa_add_node (dfa, *token, 0); - tree = create_tree (NULL, NULL, 0, new_idx); - if (BE (new_idx == -1 || tree == NULL, 0)) - return *err = REG_ESPACE, NULL; - } - /* We must return here, since ANCHORs can't be followed - by repetition operators. - eg. RE"^*" is invalid or "<ANCHOR(^)><CHAR(*)>", - it must not be "<ANCHOR(^)><REPEAT(*)>". */ - *token = fetch_token (regexp, syntax); - return tree; - case OP_PERIOD: - new_idx = re_dfa_add_node (dfa, *token, 0); - tree = create_tree (NULL, NULL, 0, new_idx); - if (BE (new_idx == -1 || tree == NULL, 0)) - return *err = REG_ESPACE, NULL; - if (MB_CUR_MAX > 1) - dfa->has_mb_node = 1; - break; - case OP_WORD: - tree = build_word_op (dfa, 0, err); - if (BE (*err != REG_NOERROR && tree == NULL, 0)) - return NULL; - break; - case OP_NOTWORD: - tree = build_word_op (dfa, 1, err); - if (BE (*err != REG_NOERROR && tree == NULL, 0)) - return NULL; - break; - case OP_ALT: - case END_OF_RE: - return NULL; - case BACK_SLASH: - *err = REG_EESCAPE; - return NULL; - default: - /* Must not happen? */ -#ifdef DEBUG - assert (0); -#endif - return NULL; - } - *token = fetch_token (regexp, syntax); - - while (token->type == OP_DUP_ASTERISK || token->type == OP_DUP_PLUS - || token->type == OP_DUP_QUESTION || token->type == OP_OPEN_DUP_NUM) - { - tree = parse_dup_op (tree, regexp, dfa, token, syntax, err); - if (BE (*err != REG_NOERROR && tree == NULL, 0)) - return NULL; - dfa->has_plural_match = 1; - } - - return tree; -} - -/* This function build the following tree, from regular expression - (<reg_exp>): - SUBEXP - | - <reg_exp> -*/ - -static bin_tree_t * -parse_sub_exp (regexp, preg, token, syntax, nest, err) - re_string_t *regexp; - regex_t *preg; - re_token_t *token; - reg_syntax_t syntax; - int nest; - reg_errcode_t *err; -{ - re_dfa_t *dfa = (re_dfa_t *) preg->buffer; - bin_tree_t *tree, *left_par, *right_par; - size_t cur_nsub; - int new_idx; - cur_nsub = preg->re_nsub++; - if (dfa->subexps_alloc < preg->re_nsub) - { - re_subexp_t *new_array; - dfa->subexps_alloc *= 2; - new_array = re_realloc (dfa->subexps, re_subexp_t, dfa->subexps_alloc); - if (BE (new_array == NULL, 0)) - { - dfa->subexps_alloc /= 2; - *err = REG_ESPACE; - return NULL; - } - dfa->subexps = new_array; - } - dfa->subexps[cur_nsub].start = dfa->nodes_len; - dfa->subexps[cur_nsub].end = -1; - - new_idx = re_dfa_add_node (dfa, *token, 0); - left_par = create_tree (NULL, NULL, 0, new_idx); - if (BE (new_idx == -1 || left_par == NULL, 0)) - return *err = REG_ESPACE, NULL; - dfa->nodes[new_idx].opr.idx = cur_nsub; - *token = fetch_token (regexp, syntax); - - /* The subexpression may be a null string. */ - if (token->type == OP_CLOSE_SUBEXP) - tree = NULL; - else - { - tree = parse_reg_exp (regexp, preg, token, syntax, nest, err); - if (BE (*err != REG_NOERROR && tree == NULL, 0)) - return NULL; - } - if (BE (token->type != OP_CLOSE_SUBEXP, 0)) - { - free_bin_tree (tree); - *err = REG_BADPAT; - return NULL; - } - new_idx = re_dfa_add_node (dfa, *token, 0); - dfa->subexps[cur_nsub].end = dfa->nodes_len; - right_par = create_tree (NULL, NULL, 0, new_idx); - tree = ((tree == NULL) ? right_par - : create_tree (tree, right_par, CONCAT, 0)); - tree = create_tree (left_par, tree, CONCAT, 0); - if (BE (new_idx == -1 || right_par == NULL || tree == NULL, 0)) - return *err = REG_ESPACE, NULL; - dfa->nodes[new_idx].opr.idx = cur_nsub; - - return tree; -} - -/* This function parse repetition operators like "*", "+", "{1,3}" etc. */ - -static bin_tree_t * -parse_dup_op (dup_elem, regexp, dfa, token, syntax, err) - bin_tree_t *dup_elem; - re_string_t *regexp; - re_dfa_t *dfa; - re_token_t *token; - reg_syntax_t syntax; - reg_errcode_t *err; -{ - re_token_t dup_token; - bin_tree_t *tree = dup_elem, *work_tree; - int new_idx, start_idx = re_string_cur_idx (regexp); - re_token_t start_token = *token; - if (token->type == OP_OPEN_DUP_NUM) - { - int i; - int end = 0; - int start = fetch_number (regexp, token, syntax); - bin_tree_t *elem; - if (start == -1) - { - if (token->type == CHARACTER && token->opr.c == ',') - start = 0; /* We treat "{,m}" as "{0,m}". */ - else - { - *err = REG_BADBR; /* <re>{} is invalid. */ - return NULL; - } - } - if (BE (start != -2, 1)) - { - /* We treat "{n}" as "{n,n}". */ - end = ((token->type == OP_CLOSE_DUP_NUM) ? start - : ((token->type == CHARACTER && token->opr.c == ',') - ? fetch_number (regexp, token, syntax) : -2)); - } - if (BE (start == -2 || end == -2, 0)) - { - /* Invalid sequence. */ - if (token->type == OP_CLOSE_DUP_NUM) - goto parse_dup_op_invalid_interval; - else - goto parse_dup_op_ebrace; - } - if (BE (start == 0 && end == 0, 0)) - { - /* We treat "<re>{0}" and "<re>{0,0}" as null string. */ - *token = fetch_token (regexp, syntax); - free_bin_tree (dup_elem); - return NULL; - } - - /* Extract "<re>{n,m}" to "<re><re>...<re><re>{0,<m-n>}". */ - elem = tree; - for (i = 0; i < start; ++i) - if (i != 0) - { - work_tree = duplicate_tree (elem, dfa); - tree = create_tree (tree, work_tree, CONCAT, 0); - if (BE (work_tree == NULL || tree == NULL, 0)) - goto parse_dup_op_espace; - } - - if (end == -1) - { - /* We treat "<re>{0,}" as "<re>*". */ - dup_token.type = OP_DUP_ASTERISK; - if (start > 0) - { - elem = duplicate_tree (elem, dfa); - new_idx = re_dfa_add_node (dfa, dup_token, 0); - work_tree = create_tree (elem, NULL, 0, new_idx); - tree = create_tree (tree, work_tree, CONCAT, 0); - if (BE (elem == NULL || new_idx == -1 || work_tree == NULL - || tree == NULL, 0)) - goto parse_dup_op_espace; - } - else - { - new_idx = re_dfa_add_node (dfa, dup_token, 0); - tree = create_tree (elem, NULL, 0, new_idx); - if (BE (new_idx == -1 || tree == NULL, 0)) - goto parse_dup_op_espace; - } - } - else if (end - start > 0) - { - /* Then extract "<re>{0,m}" to "<re>?<re>?...<re>?". */ - dup_token.type = OP_DUP_QUESTION; - if (start > 0) - { - elem = duplicate_tree (elem, dfa); - new_idx = re_dfa_add_node (dfa, dup_token, 0); - elem = create_tree (elem, NULL, 0, new_idx); - tree = create_tree (tree, elem, CONCAT, 0); - if (BE (elem == NULL || new_idx == -1 || tree == NULL, 0)) - goto parse_dup_op_espace; - } - else - { - new_idx = re_dfa_add_node (dfa, dup_token, 0); - tree = elem = create_tree (elem, NULL, 0, new_idx); - if (BE (new_idx == -1 || tree == NULL, 0)) - goto parse_dup_op_espace; - } - for (i = 1; i < end - start; ++i) - { - work_tree = duplicate_tree (elem, dfa); - tree = create_tree (tree, work_tree, CONCAT, 0); - if (BE (work_tree == NULL || tree == NULL, 0)) - return *err = REG_ESPACE, NULL; - } - } - } - else - { - new_idx = re_dfa_add_node (dfa, *token, 0); - tree = create_tree (tree, NULL, 0, new_idx); - if (BE (new_idx == -1 || tree == NULL, 0)) - return *err = REG_ESPACE, NULL; - } - *token = fetch_token (regexp, syntax); - return tree; - - parse_dup_op_espace: - free_bin_tree (tree); - *err = REG_ESPACE; - return NULL; - - parse_dup_op_ebrace: - if (BE (!(syntax & RE_INVALID_INTERVAL_ORD), 0)) - { - *err = REG_EBRACE; - return NULL; - } - goto parse_dup_op_rollback; - parse_dup_op_invalid_interval: - if (BE (!(syntax & RE_INVALID_INTERVAL_ORD), 0)) - { - *err = REG_BADBR; - return NULL; - } - parse_dup_op_rollback: - re_string_set_index (regexp, start_idx); - *token = start_token; - token->type = CHARACTER; - return dup_elem; -} - -/* Size of the names for collating symbol/equivalence_class/character_class. - I'm not sure, but maybe enough. */ -#define BRACKET_NAME_BUF_SIZE 32 - -#ifndef _LIBC - /* Local function for parse_bracket_exp only used in case of NOT _LIBC. - Build the range expression which starts from START_ELEM, and ends - at END_ELEM. The result are written to MBCSET and SBCSET. - RANGE_ALLOC is the allocated size of mbcset->range_starts, and - mbcset->range_ends, is a pointer argument sinse we may - update it. */ - -static reg_errcode_t -# ifdef RE_ENABLE_I18N -build_range_exp (sbcset, mbcset, range_alloc, start_elem, end_elem) - re_charset_t *mbcset; - int *range_alloc; -# else /* not RE_ENABLE_I18N */ -build_range_exp (sbcset, start_elem, end_elem) -# endif /* not RE_ENABLE_I18N */ - re_bitset_ptr_t sbcset; - bracket_elem_t *start_elem, *end_elem; -{ - unsigned int start_ch, end_ch; - /* Equivalence Classes and Character Classes can't be a range start/end. */ - if (BE (start_elem->type == EQUIV_CLASS || start_elem->type == CHAR_CLASS - || end_elem->type == EQUIV_CLASS || end_elem->type == CHAR_CLASS, - 0)) - return REG_ERANGE; - - /* We can handle no multi character collating elements without libc - support. */ - if (BE ((start_elem->type == COLL_SYM - && strlen ((char *) start_elem->opr.name) > 1) - || (end_elem->type == COLL_SYM - && strlen ((char *) end_elem->opr.name) > 1), 0)) - return REG_ECOLLATE; - -# ifdef RE_ENABLE_I18N - { - wchar_t wc, start_wc, end_wc; - wchar_t cmp_buf[6] = {L'\0', L'\0', L'\0', L'\0', L'\0', L'\0'}; - - start_ch = ((start_elem->type == SB_CHAR) ? start_elem->opr.ch - : ((start_elem->type == COLL_SYM) ? start_elem->opr.name[0] - : 0)); - end_ch = ((end_elem->type == SB_CHAR) ? end_elem->opr.ch - : ((end_elem->type == COLL_SYM) ? end_elem->opr.name[0] - : 0)); - start_wc = ((start_elem->type == SB_CHAR || start_elem->type == COLL_SYM) - ? __btowc (start_ch) : start_elem->opr.wch); - end_wc = ((end_elem->type == SB_CHAR || end_elem->type == COLL_SYM) - ? __btowc (end_ch) : end_elem->opr.wch); - cmp_buf[0] = start_wc; - cmp_buf[4] = end_wc; - if (wcscoll (cmp_buf, cmp_buf + 4) > 0) - return REG_ERANGE; - - /* Check the space of the arrays. */ - if (*range_alloc == mbcset->nranges) - { - /* There are not enough space, need realloc. */ - wchar_t *new_array_start, *new_array_end; - int new_nranges; - - /* +1 in case of mbcset->nranges is 0. */ - new_nranges = 2 * mbcset->nranges + 1; - /* Use realloc since mbcset->range_starts and mbcset->range_ends - are NULL if *range_alloc == 0. */ - new_array_start = re_realloc (mbcset->range_starts, wchar_t, - new_nranges); - new_array_end = re_realloc (mbcset->range_ends, wchar_t, - new_nranges); - - if (BE (new_array_start == NULL || new_array_end == NULL, 0)) - return REG_ESPACE; - - mbcset->range_starts = new_array_start; - mbcset->range_ends = new_array_end; - *range_alloc = new_nranges; - } - - mbcset->range_starts[mbcset->nranges] = start_wc; - mbcset->range_ends[mbcset->nranges++] = end_wc; - - /* Build the table for single byte characters. */ - for (wc = 0; wc <= SBC_MAX; ++wc) - { - cmp_buf[2] = wc; - if (wcscoll (cmp_buf, cmp_buf + 2) <= 0 - && wcscoll (cmp_buf + 2, cmp_buf + 4) <= 0) - bitset_set (sbcset, wc); - } - } -# else /* not RE_ENABLE_I18N */ - { - unsigned int ch; - start_ch = ((start_elem->type == SB_CHAR ) ? start_elem->opr.ch - : ((start_elem->type == COLL_SYM) ? start_elem->opr.name[0] - : 0)); - end_ch = ((end_elem->type == SB_CHAR ) ? end_elem->opr.ch - : ((end_elem->type == COLL_SYM) ? end_elem->opr.name[0] - : 0)); - if (start_ch > end_ch) - return REG_ERANGE; - /* Build the table for single byte characters. */ - for (ch = 0; ch <= SBC_MAX; ++ch) - if (start_ch <= ch && ch <= end_ch) - bitset_set (sbcset, ch); - } -# endif /* not RE_ENABLE_I18N */ - return REG_NOERROR; -} -#endif /* not _LIBC */ - -#ifndef _LIBC -/* Helper function for parse_bracket_exp only used in case of NOT _LIBC.. - Build the collating element which is represented by NAME. - The result are written to MBCSET and SBCSET. - COLL_SYM_ALLOC is the allocated size of mbcset->coll_sym, is a - pointer argument since we may update it. */ - -static reg_errcode_t -# ifdef RE_ENABLE_I18N -build_collating_symbol (sbcset, mbcset, coll_syxmalloc, name) - re_charset_t *mbcset; - int *coll_syxmalloc; -# else /* not RE_ENABLE_I18N */ -build_collating_symbol (sbcset, name) -# endif /* not RE_ENABLE_I18N */ - re_bitset_ptr_t sbcset; - const unsigned char *name; -{ - size_t name_len = strlen ((const char *) name); - if (BE (name_len != 1, 0)) - return REG_ECOLLATE; - else - { - bitset_set (sbcset, name[0]); - return REG_NOERROR; - } -} -#endif /* not _LIBC */ - -/* This function parse bracket expression like "[abc]", "[a-c]", - "[[.a-a.]]" etc. */ - -static bin_tree_t * -parse_bracket_exp (regexp, dfa, token, syntax, err) - re_string_t *regexp; - re_dfa_t *dfa; - re_token_t *token; - reg_syntax_t syntax; - reg_errcode_t *err; -{ -#ifdef _LIBC - const unsigned char *collseqmb; - const char *collseqwc; - uint32_t nrules; - int32_t table_size; - const int32_t *symb_table; - const unsigned char *extra; - - /* Local function for parse_bracket_exp used in _LIBC environement. - Seek the collating symbol entry correspondings to NAME. - Return the index of the symbol in the SYMB_TABLE. */ - - static inline int32_t - seek_collating_symbol_entry (name, name_len) - const unsigned char *name; - size_t name_len; - { - int32_t hash = elem_hash ((const char *) name, name_len); - int32_t elem = hash % table_size; - int32_t second = hash % (table_size - 2); - while (symb_table[2 * elem] != 0) - { - /* First compare the hashing value. */ - if (symb_table[2 * elem] == hash - /* Compare the length of the name. */ - && name_len == extra[symb_table[2 * elem + 1]] - /* Compare the name. */ - && memcmp (name, &extra[symb_table[2 * elem + 1] + 1], - name_len) == 0) - { - /* Yep, this is the entry. */ - break; - } - - /* Next entry. */ - elem += second; - } - return elem; - } - - /* Local function for parse_bracket_exp used in _LIBC environement. - Look up the collation sequence value of BR_ELEM. - Return the value if succeeded, UINT_MAX otherwise. */ - - static inline unsigned int - lookup_collation_sequence_value (br_elem) - bracket_elem_t *br_elem; - { - if (br_elem->type == SB_CHAR) - { - /* - if (MB_CUR_MAX == 1) - */ - if (nrules == 0) - return collseqmb[br_elem->opr.ch]; - else - { - wint_t wc = __btowc (br_elem->opr.ch); - return collseq_table_lookup (collseqwc, wc); - } - } - else if (br_elem->type == MB_CHAR) - { - return collseq_table_lookup (collseqwc, br_elem->opr.wch); - } - else if (br_elem->type == COLL_SYM) - { - size_t sym_name_len = strlen ((char *) br_elem->opr.name); - if (nrules != 0) - { - int32_t elem, idx; - elem = seek_collating_symbol_entry (br_elem->opr.name, - sym_name_len); - if (symb_table[2 * elem] != 0) - { - /* We found the entry. */ - idx = symb_table[2 * elem + 1]; - /* Skip the name of collating element name. */ - idx += 1 + extra[idx]; - /* Skip the byte sequence of the collating element. */ - idx += 1 + extra[idx]; - /* Adjust for the alignment. */ - idx = (idx + 3) & ~3; - /* Skip the multibyte collation sequence value. */ - idx += sizeof (unsigned int); - /* Skip the wide char sequence of the collating element. */ - idx += sizeof (unsigned int) * - (1 + *(unsigned int *) (extra + idx)); - /* Return the collation sequence value. */ - return *(unsigned int *) (extra + idx); - } - else if (symb_table[2 * elem] == 0 && sym_name_len == 1) - { - /* No valid character. Match it as a single byte - character. */ - return collseqmb[br_elem->opr.name[0]]; - } - } - else if (sym_name_len == 1) - return collseqmb[br_elem->opr.name[0]]; - } - return UINT_MAX; - } - - /* Local function for parse_bracket_exp used in _LIBC environement. - Build the range expression which starts from START_ELEM, and ends - at END_ELEM. The result are written to MBCSET and SBCSET. - RANGE_ALLOC is the allocated size of mbcset->range_starts, and - mbcset->range_ends, is a pointer argument sinse we may - update it. */ - - static inline reg_errcode_t -# ifdef RE_ENABLE_I18N - build_range_exp (sbcset, mbcset, range_alloc, start_elem, end_elem) - re_charset_t *mbcset; - int *range_alloc; -# else /* not RE_ENABLE_I18N */ - build_range_exp (sbcset, start_elem, end_elem) -# endif /* not RE_ENABLE_I18N */ - re_bitset_ptr_t sbcset; - bracket_elem_t *start_elem, *end_elem; - { - unsigned int ch; - uint32_t start_collseq; - uint32_t end_collseq; - -# ifdef RE_ENABLE_I18N - /* Check the space of the arrays. */ - if (*range_alloc == mbcset->nranges) - { - /* There are not enough space, need realloc. */ - uint32_t *new_array_start; - uint32_t *new_array_end; - int new_nranges; - - /* +1 in case of mbcset->nranges is 0. */ - new_nranges = 2 * mbcset->nranges + 1; - /* Use realloc since mbcset->range_starts and mbcset->range_ends - are NULL if *range_alloc == 0. */ - new_array_start = re_realloc (mbcset->range_starts, uint32_t, - new_nranges); - new_array_end = re_realloc (mbcset->range_ends, uint32_t, - new_nranges); - - if (BE (new_array_start == NULL || new_array_end == NULL, 0)) - return REG_ESPACE; - - mbcset->range_starts = new_array_start; - mbcset->range_ends = new_array_end; - *range_alloc = new_nranges; - } -# endif /* RE_ENABLE_I18N */ - - /* Equivalence Classes and Character Classes can't be a range - start/end. */ - if (BE (start_elem->type == EQUIV_CLASS || start_elem->type == CHAR_CLASS - || end_elem->type == EQUIV_CLASS || end_elem->type == CHAR_CLASS, - 0)) - return REG_ERANGE; - - start_collseq = lookup_collation_sequence_value (start_elem); - end_collseq = lookup_collation_sequence_value (end_elem); - /* Check start/end collation sequence values. */ - if (BE (start_collseq == UINT_MAX || end_collseq == UINT_MAX, 0)) - return REG_ECOLLATE; - if (BE ((syntax & RE_NO_EMPTY_RANGES) && start_collseq > end_collseq, 0)) - return REG_ERANGE; - -# ifdef RE_ENABLE_I18N - /* Got valid collation sequence values, add them as a new entry. */ - mbcset->range_starts[mbcset->nranges] = start_collseq; - mbcset->range_ends[mbcset->nranges++] = end_collseq; -# endif /* RE_ENABLE_I18N */ - - /* Build the table for single byte characters. */ - for (ch = 0; ch <= SBC_MAX; ch++) - { - uint32_t ch_collseq; - /* - if (MB_CUR_MAX == 1) - */ - if (nrules == 0) - ch_collseq = collseqmb[ch]; - else - ch_collseq = collseq_table_lookup (collseqwc, __btowc (ch)); - if (start_collseq <= ch_collseq && ch_collseq <= end_collseq) - bitset_set (sbcset, ch); - } - return REG_NOERROR; - } - - /* Local function for parse_bracket_exp used in _LIBC environement. - Build the collating element which is represented by NAME. - The result are written to MBCSET and SBCSET. - COLL_SYM_ALLOC is the allocated size of mbcset->coll_sym, is a - pointer argument sinse we may update it. */ - - static inline reg_errcode_t -# ifdef RE_ENABLE_I18N - build_collating_symbol (sbcset, mbcset, coll_syxmalloc, name) - re_charset_t *mbcset; - int *coll_syxmalloc; -# else /* not RE_ENABLE_I18N */ - build_collating_symbol (sbcset, name) -# endif /* not RE_ENABLE_I18N */ - re_bitset_ptr_t sbcset; - const unsigned char *name; - { - int32_t elem, idx; - size_t name_len = strlen ((const char *) name); - if (nrules != 0) - { - elem = seek_collating_symbol_entry (name, name_len); - if (symb_table[2 * elem] != 0) - { - /* We found the entry. */ - idx = symb_table[2 * elem + 1]; - /* Skip the name of collating element name. */ - idx += 1 + extra[idx]; - } - else if (symb_table[2 * elem] == 0 && name_len == 1) - { - /* No valid character, treat it as a normal - character. */ - bitset_set (sbcset, name[0]); - return REG_NOERROR; - } - else - return REG_ECOLLATE; - -# ifdef RE_ENABLE_I18N - /* Got valid collation sequence, add it as a new entry. */ - /* Check the space of the arrays. */ - if (*coll_syxmalloc == mbcset->ncoll_syms) - { - /* Not enough, realloc it. */ - /* +1 in case of mbcset->ncoll_syms is 0. */ - *coll_syxmalloc = 2 * mbcset->ncoll_syms + 1; - /* Use realloc since mbcset->coll_syms is NULL - if *alloc == 0. */ - mbcset->coll_syms = re_realloc (mbcset->coll_syms, int32_t, - *coll_syxmalloc); - if (BE (mbcset->coll_syms == NULL, 0)) - return REG_ESPACE; - } - mbcset->coll_syms[mbcset->ncoll_syms++] = idx; -# endif /* RE_ENABLE_I18N */ - return REG_NOERROR; - } - else - { - if (BE (name_len != 1, 0)) - return REG_ECOLLATE; - else - { - bitset_set (sbcset, name[0]); - return REG_NOERROR; - } - } - } -#endif - - re_token_t br_token; - re_bitset_ptr_t sbcset; -#ifdef RE_ENABLE_I18N - re_charset_t *mbcset; - int coll_syxmalloc = 0, range_alloc = 0, mbchar_alloc = 0; - int equiv_class_alloc = 0, char_class_alloc = 0; -#else /* not RE_ENABLE_I18N */ - int non_match = 0; -#endif /* not RE_ENABLE_I18N */ - bin_tree_t *work_tree; - int token_len, new_idx; -#ifdef _LIBC - collseqmb = (const unsigned char *) - _NL_CURRENT (LC_COLLATE, _NL_COLLATE_COLLSEQMB); - nrules = _NL_CURRENT_WORD (LC_COLLATE, _NL_COLLATE_NRULES); - if (nrules) - { - /* - if (MB_CUR_MAX > 1) - */ - collseqwc = _NL_CURRENT (LC_COLLATE, _NL_COLLATE_COLLSEQWC); - table_size = _NL_CURRENT_WORD (LC_COLLATE, _NL_COLLATE_SYMB_HASH_SIZEMB); - symb_table = (const int32_t *) _NL_CURRENT (LC_COLLATE, - _NL_COLLATE_SYMB_TABLEMB); - extra = (const unsigned char *) _NL_CURRENT (LC_COLLATE, - _NL_COLLATE_SYMB_EXTRAMB); - } -#endif - sbcset = (re_bitset_ptr_t) calloc (sizeof (unsigned int), BITSET_UINTS); -#ifdef RE_ENABLE_I18N - mbcset = (re_charset_t *) calloc (sizeof (re_charset_t), 1); -#endif /* RE_ENABLE_I18N */ -#ifdef RE_ENABLE_I18N - if (BE (sbcset == NULL || mbcset == NULL, 0)) -#else - if (BE (sbcset == NULL, 0)) -#endif /* RE_ENABLE_I18N */ - { - *err = REG_ESPACE; - return NULL; - } - - token_len = peek_token_bracket (token, regexp, syntax); - if (BE (token->type == END_OF_RE, 0)) - { - *err = REG_BADPAT; - goto parse_bracket_exp_free_return; - } - if (token->type == OP_NON_MATCH_LIST) - { -#ifdef RE_ENABLE_I18N - int i; - mbcset->non_match = 1; -#else /* not RE_ENABLE_I18N */ - non_match = 1; -#endif /* not RE_ENABLE_I18N */ - if (syntax & RE_HAT_LISTS_NOT_NEWLINE) - bitset_set (sbcset, '\0'); - re_string_skip_bytes (regexp, token_len); /* Skip a token. */ - token_len = peek_token_bracket (token, regexp, syntax); - if (BE (token->type == END_OF_RE, 0)) - { - *err = REG_BADPAT; - goto parse_bracket_exp_free_return; - } -#ifdef RE_ENABLE_I18N - if (MB_CUR_MAX > 1) - for (i = 0; i < SBC_MAX; ++i) - if (__btowc (i) == WEOF) - bitset_set (sbcset, i); -#endif /* RE_ENABLE_I18N */ - } - - /* We treat the first ']' as a normal character. */ - if (token->type == OP_CLOSE_BRACKET) - token->type = CHARACTER; - - while (1) - { - bracket_elem_t start_elem, end_elem; - unsigned char start_name_buf[BRACKET_NAME_BUF_SIZE]; - unsigned char end_name_buf[BRACKET_NAME_BUF_SIZE]; - reg_errcode_t ret; - int token_len2 = 0, is_range_exp = 0; - re_token_t token2; - - start_elem.opr.name = start_name_buf; - ret = parse_bracket_element (&start_elem, regexp, token, token_len, dfa, - syntax); - if (BE (ret != REG_NOERROR, 0)) - { - *err = ret; - goto parse_bracket_exp_free_return; - } - - token_len = peek_token_bracket (token, regexp, syntax); - if (BE (token->type == END_OF_RE, 0)) - { - *err = REG_BADPAT; - goto parse_bracket_exp_free_return; - } - if (token->type == OP_CHARSET_RANGE) - { - re_string_skip_bytes (regexp, token_len); /* Skip '-'. */ - token_len2 = peek_token_bracket (&token2, regexp, syntax); - if (BE (token->type == END_OF_RE, 0)) - { - *err = REG_BADPAT; - goto parse_bracket_exp_free_return; - } - if (token2.type == OP_CLOSE_BRACKET) - { - /* We treat the last '-' as a normal character. */ - re_string_skip_bytes (regexp, -token_len); - token->type = CHARACTER; - } - else - is_range_exp = 1; - } - - if (is_range_exp == 1) - { - end_elem.opr.name = end_name_buf; - ret = parse_bracket_element (&end_elem, regexp, &token2, token_len2, - dfa, syntax); - if (BE (ret != REG_NOERROR, 0)) - { - *err = ret; - goto parse_bracket_exp_free_return; - } - - token_len = peek_token_bracket (token, regexp, syntax); - if (BE (token->type == END_OF_RE, 0)) - { - *err = REG_BADPAT; - goto parse_bracket_exp_free_return; - } - *err = build_range_exp (sbcset, -#ifdef RE_ENABLE_I18N - mbcset, &range_alloc, -#endif /* RE_ENABLE_I18N */ - &start_elem, &end_elem); - if (BE (*err != REG_NOERROR, 0)) - goto parse_bracket_exp_free_return; - } - else - { - switch (start_elem.type) - { - case SB_CHAR: - bitset_set (sbcset, start_elem.opr.ch); - break; -#ifdef RE_ENABLE_I18N - case MB_CHAR: - /* Check whether the array has enough space. */ - if (mbchar_alloc == mbcset->nmbchars) - { - /* Not enough, realloc it. */ - /* +1 in case of mbcset->nmbchars is 0. */ - mbchar_alloc = 2 * mbcset->nmbchars + 1; - /* Use realloc since array is NULL if *alloc == 0. */ - mbcset->mbchars = re_realloc (mbcset->mbchars, wchar_t, - mbchar_alloc); - if (BE (mbcset->mbchars == NULL, 0)) - goto parse_bracket_exp_espace; - } - mbcset->mbchars[mbcset->nmbchars++] = start_elem.opr.wch; - break; -#endif /* RE_ENABLE_I18N */ - case EQUIV_CLASS: - *err = build_equiv_class (sbcset, -#ifdef RE_ENABLE_I18N - mbcset, &equiv_class_alloc, -#endif /* RE_ENABLE_I18N */ - start_elem.opr.name); - if (BE (*err != REG_NOERROR, 0)) - goto parse_bracket_exp_free_return; - break; - case COLL_SYM: - *err = build_collating_symbol (sbcset, -#ifdef RE_ENABLE_I18N - mbcset, &coll_syxmalloc, -#endif /* RE_ENABLE_I18N */ - start_elem.opr.name); - if (BE (*err != REG_NOERROR, 0)) - goto parse_bracket_exp_free_return; - break; - case CHAR_CLASS: - ret = build_charclass (sbcset, -#ifdef RE_ENABLE_I18N - mbcset, &char_class_alloc, -#endif /* RE_ENABLE_I18N */ - start_elem.opr.name, syntax); - if (BE (ret != REG_NOERROR, 0)) - goto parse_bracket_exp_espace; - break; - default: - assert (0); - break; - } - } - if (token->type == OP_CLOSE_BRACKET) - break; - } - - re_string_skip_bytes (regexp, token_len); /* Skip a token. */ - - /* If it is non-matching list. */ -#ifdef RE_ENABLE_I18N - if (mbcset->non_match) -#else /* not RE_ENABLE_I18N */ - if (non_match) -#endif /* not RE_ENABLE_I18N */ - bitset_not (sbcset); - - /* Build a tree for simple bracket. */ - br_token.type = SIMPLE_BRACKET; - br_token.opr.sbcset = sbcset; - new_idx = re_dfa_add_node (dfa, br_token, 0); - work_tree = create_tree (NULL, NULL, 0, new_idx); - if (BE (new_idx == -1 || work_tree == NULL, 0)) - goto parse_bracket_exp_espace; - -#ifdef RE_ENABLE_I18N - if (mbcset->nmbchars || mbcset->ncoll_syms || mbcset->nequiv_classes - || mbcset->nranges || (MB_CUR_MAX > 1 && (mbcset->nchar_classes - || mbcset->non_match))) - { - re_token_t alt_token; - bin_tree_t *mbc_tree; - /* Build a tree for complex bracket. */ - br_token.type = COMPLEX_BRACKET; - br_token.opr.mbcset = mbcset; - dfa->has_mb_node = 1; - new_idx = re_dfa_add_node (dfa, br_token, 0); - mbc_tree = create_tree (NULL, NULL, 0, new_idx); - if (BE (new_idx == -1 || mbc_tree == NULL, 0)) - goto parse_bracket_exp_espace; - /* Then join them by ALT node. */ - dfa->has_plural_match = 1; - alt_token.type = OP_ALT; - new_idx = re_dfa_add_node (dfa, alt_token, 0); - work_tree = create_tree (work_tree, mbc_tree, 0, new_idx); - if (BE (new_idx != -1 && mbc_tree != NULL, 1)) - return work_tree; - } - else - { - free_charset (mbcset); - return work_tree; - } -#else /* not RE_ENABLE_I18N */ - return work_tree; -#endif /* not RE_ENABLE_I18N */ - - parse_bracket_exp_espace: - *err = REG_ESPACE; - parse_bracket_exp_free_return: - re_free (sbcset); -#ifdef RE_ENABLE_I18N - free_charset (mbcset); -#endif /* RE_ENABLE_I18N */ - return NULL; -} - -/* Parse an element in the bracket expression. */ - -static reg_errcode_t -parse_bracket_element (elem, regexp, token, token_len, dfa, syntax) - bracket_elem_t *elem; - re_string_t *regexp; - re_token_t *token; - int token_len; - re_dfa_t *dfa; - reg_syntax_t syntax; -{ -#ifdef RE_ENABLE_I18N - int cur_char_size; - cur_char_size = re_string_char_size_at (regexp, re_string_cur_idx (regexp)); - if (cur_char_size > 1) - { - elem->type = MB_CHAR; - elem->opr.wch = re_string_wchar_at (regexp, re_string_cur_idx (regexp)); - re_string_skip_bytes (regexp, cur_char_size); - return REG_NOERROR; - } -#endif /* RE_ENABLE_I18N */ - re_string_skip_bytes (regexp, token_len); /* Skip a token. */ - if (token->type == OP_OPEN_COLL_ELEM || token->type == OP_OPEN_CHAR_CLASS - || token->type == OP_OPEN_EQUIV_CLASS) - return parse_bracket_symbol (elem, regexp, token); - elem->type = SB_CHAR; - elem->opr.ch = token->opr.c; - return REG_NOERROR; -} - -/* Parse a bracket symbol in the bracket expression. Bracket symbols are - such as [:<character_class>:], [.<collating_element>.], and - [=<equivalent_class>=]. */ - -static reg_errcode_t -parse_bracket_symbol (elem, regexp, token) - bracket_elem_t *elem; - re_string_t *regexp; - re_token_t *token; -{ - unsigned char ch, delim = token->opr.c; - int i = 0; - for (;; ++i) - { - if (re_string_eoi(regexp) || i >= BRACKET_NAME_BUF_SIZE) - return REG_EBRACK; - if (token->type == OP_OPEN_CHAR_CLASS) - ch = re_string_fetch_byte_case (regexp); - else - ch = re_string_fetch_byte (regexp); - if (ch == delim && re_string_peek_byte (regexp, 0) == ']') - break; - elem->opr.name[i] = ch; - } - re_string_skip_bytes (regexp, 1); - elem->opr.name[i] = '\0'; - switch (token->type) - { - case OP_OPEN_COLL_ELEM: - elem->type = COLL_SYM; - break; - case OP_OPEN_EQUIV_CLASS: - elem->type = EQUIV_CLASS; - break; - case OP_OPEN_CHAR_CLASS: - elem->type = CHAR_CLASS; - break; - default: - break; - } - return REG_NOERROR; -} - - /* Helper function for parse_bracket_exp. - Build the equivalence class which is represented by NAME. - The result are written to MBCSET and SBCSET. - EQUIV_CLASS_ALLOC is the allocated size of mbcset->equiv_classes, - is a pointer argument sinse we may update it. */ - -static reg_errcode_t -#ifdef RE_ENABLE_I18N -build_equiv_class (sbcset, mbcset, equiv_class_alloc, name) - re_charset_t *mbcset; - int *equiv_class_alloc; -#else /* not RE_ENABLE_I18N */ -build_equiv_class (sbcset, name) -#endif /* not RE_ENABLE_I18N */ - re_bitset_ptr_t sbcset; - const unsigned char *name; -{ -#if defined _LIBC && defined RE_ENABLE_I18N - uint32_t nrules = _NL_CURRENT_WORD (LC_COLLATE, _NL_COLLATE_NRULES); - if (nrules != 0) - { - const int32_t *table, *indirect; - const unsigned char *weights, *extra, *cp; - unsigned char char_buf[2]; - int32_t idx1, idx2; - unsigned int ch; - size_t len; - /* This #include defines a local function! */ -# include <locale/weight.h> - /* Calculate the index for equivalence class. */ - cp = name; - table = (const int32_t *) _NL_CURRENT (LC_COLLATE, _NL_COLLATE_TABLEMB); - weights = (const unsigned char *) _NL_CURRENT (LC_COLLATE, - _NL_COLLATE_WEIGHTMB); - extra = (const unsigned char *) _NL_CURRENT (LC_COLLATE, - _NL_COLLATE_EXTRAMB); - indirect = (const int32_t *) _NL_CURRENT (LC_COLLATE, - _NL_COLLATE_INDIRECTMB); - idx1 = findidx (&cp); - if (BE (idx1 == 0 || cp < name + strlen ((const char *) name), 0)) - /* This isn't a valid character. */ - return REG_ECOLLATE; - - /* Build single byte matcing table for this equivalence class. */ - char_buf[1] = (unsigned char) '\0'; - len = weights[idx1]; - for (ch = 0; ch < SBC_MAX; ++ch) - { - char_buf[0] = ch; - cp = char_buf; - idx2 = findidx (&cp); -/* - idx2 = table[ch]; -*/ - if (idx2 == 0) - /* This isn't a valid character. */ - continue; - if (len == weights[idx2]) - { - int cnt = 0; - while (cnt <= len && - weights[idx1 + 1 + cnt] == weights[idx2 + 1 + cnt]) - ++cnt; - - if (cnt > len) - bitset_set (sbcset, ch); - } - } - /* Check whether the array has enough space. */ - if (*equiv_class_alloc == mbcset->nequiv_classes) - { - /* Not enough, realloc it. */ - /* +1 in case of mbcset->nequiv_classes is 0. */ - *equiv_class_alloc = 2 * mbcset->nequiv_classes + 1; - /* Use realloc since the array is NULL if *alloc == 0. */ - mbcset->equiv_classes = re_realloc (mbcset->equiv_classes, int32_t, - *equiv_class_alloc); - if (BE (mbcset->equiv_classes == NULL, 0)) - return REG_ESPACE; - } - mbcset->equiv_classes[mbcset->nequiv_classes++] = idx1; - } - else -#endif /* _LIBC && RE_ENABLE_I18N */ - { - if (BE (strlen ((const char *) name) != 1, 0)) - return REG_ECOLLATE; - bitset_set (sbcset, *name); - } - return REG_NOERROR; -} - - /* Helper function for parse_bracket_exp. - Build the character class which is represented by NAME. - The result are written to MBCSET and SBCSET. - CHAR_CLASS_ALLOC is the allocated size of mbcset->char_classes, - is a pointer argument sinse we may update it. */ - -static reg_errcode_t -#ifdef RE_ENABLE_I18N -build_charclass (sbcset, mbcset, char_class_alloc, class_name, syntax) - re_charset_t *mbcset; - int *char_class_alloc; -#else /* not RE_ENABLE_I18N */ -build_charclass (sbcset, class_name, syntax) -#endif /* not RE_ENABLE_I18N */ - re_bitset_ptr_t sbcset; - const unsigned char *class_name; - reg_syntax_t syntax; -{ - int i; - const char *name = (const char *) class_name; - - /* In case of REG_ICASE "upper" and "lower" match the both of - upper and lower cases. */ - if ((syntax & RE_ICASE) - && (strcmp (name, "upper") == 0 || strcmp (name, "lower") == 0)) - name = "alpha"; - -#ifdef RE_ENABLE_I18N - /* Check the space of the arrays. */ - if (*char_class_alloc == mbcset->nchar_classes) - { - /* Not enough, realloc it. */ - /* +1 in case of mbcset->nchar_classes is 0. */ - *char_class_alloc = 2 * mbcset->nchar_classes + 1; - /* Use realloc since array is NULL if *alloc == 0. */ - mbcset->char_classes = re_realloc (mbcset->char_classes, wctype_t, - *char_class_alloc); - if (BE (mbcset->char_classes == NULL, 0)) - return REG_ESPACE; - } - mbcset->char_classes[mbcset->nchar_classes++] = __wctype (name); -#endif /* RE_ENABLE_I18N */ - -#define BUILD_CHARCLASS_LOOP(ctype_func)\ - for (i = 0; i < SBC_MAX; ++i) \ - { \ - if (ctype_func (i)) \ - bitset_set (sbcset, i); \ - } - - if (strcmp (name, "alnum") == 0) - BUILD_CHARCLASS_LOOP (isalnum) - else if (strcmp (name, "cntrl") == 0) - BUILD_CHARCLASS_LOOP (iscntrl) - else if (strcmp (name, "lower") == 0) - BUILD_CHARCLASS_LOOP (islower) - else if (strcmp (name, "space") == 0) - BUILD_CHARCLASS_LOOP (isspace) - else if (strcmp (name, "alpha") == 0) - BUILD_CHARCLASS_LOOP (isalpha) - else if (strcmp (name, "digit") == 0) - BUILD_CHARCLASS_LOOP (isdigit) - else if (strcmp (name, "print") == 0) - BUILD_CHARCLASS_LOOP (isprint) - else if (strcmp (name, "upper") == 0) - BUILD_CHARCLASS_LOOP (isupper) - else if (strcmp (name, "blank") == 0) - BUILD_CHARCLASS_LOOP (isblank) - else if (strcmp (name, "graph") == 0) - BUILD_CHARCLASS_LOOP (isgraph) - else if (strcmp (name, "punct") == 0) - BUILD_CHARCLASS_LOOP (ispunct) - else if (strcmp (name, "xdigit") == 0) - BUILD_CHARCLASS_LOOP (isxdigit) - else - return REG_ECTYPE; - - return REG_NOERROR; -} - -static bin_tree_t * -build_word_op (dfa, not, err) - re_dfa_t *dfa; - int not; - reg_errcode_t *err; -{ - re_bitset_ptr_t sbcset; -#ifdef RE_ENABLE_I18N - re_charset_t *mbcset; - int alloc = 0; -#else /* not RE_ENABLE_I18N */ - int non_match = 0; -#endif /* not RE_ENABLE_I18N */ - reg_errcode_t ret; - re_token_t br_token; - bin_tree_t *tree; - int new_idx; - - sbcset = (re_bitset_ptr_t) calloc (sizeof (unsigned int), BITSET_UINTS); -#ifdef RE_ENABLE_I18N - mbcset = (re_charset_t *) calloc (sizeof (re_charset_t), 1); -#endif /* RE_ENABLE_I18N */ - -#ifdef RE_ENABLE_I18N - if (BE (sbcset == NULL || mbcset == NULL, 0)) -#else /* not RE_ENABLE_I18N */ - if (BE (sbcset == NULL, 0)) -#endif /* not RE_ENABLE_I18N */ - { - *err = REG_ESPACE; - return NULL; - } - - if (not) - { -#ifdef RE_ENABLE_I18N - int i; - /* - if (syntax & RE_HAT_LISTS_NOT_NEWLINE) - bitset_set(cset->sbcset, '\0'); - */ - mbcset->non_match = 1; - if (MB_CUR_MAX > 1) - for (i = 0; i < SBC_MAX; ++i) - if (__btowc (i) == WEOF) - bitset_set (sbcset, i); -#else /* not RE_ENABLE_I18N */ - non_match = 1; -#endif /* not RE_ENABLE_I18N */ - } - - /* We don't care the syntax in this case. */ - ret = build_charclass (sbcset, -#ifdef RE_ENABLE_I18N - mbcset, &alloc, -#endif /* RE_ENABLE_I18N */ - (const unsigned char *) "alpha", 0); - - if (BE (ret != REG_NOERROR, 0)) - { - re_free (sbcset); -#ifdef RE_ENABLE_I18N - free_charset (mbcset); -#endif /* RE_ENABLE_I18N */ - *err = REG_ESPACE; - return NULL; - } - /* \w match '_' also. */ - bitset_set (sbcset, '_'); - - /* If it is non-matching list. */ -#ifdef RE_ENABLE_I18N - if (mbcset->non_match) -#else /* not RE_ENABLE_I18N */ - if (non_match) -#endif /* not RE_ENABLE_I18N */ - bitset_not (sbcset); - - /* Build a tree for simple bracket. */ - br_token.type = SIMPLE_BRACKET; - br_token.opr.sbcset = sbcset; - new_idx = re_dfa_add_node (dfa, br_token, 0); - tree = create_tree (NULL, NULL, 0, new_idx); - if (BE (new_idx == -1 || tree == NULL, 0)) - goto build_word_op_espace; - -#ifdef RE_ENABLE_I18N - if (MB_CUR_MAX > 1) - { - re_token_t alt_token; - bin_tree_t *mbc_tree; - /* Build a tree for complex bracket. */ - br_token.type = COMPLEX_BRACKET; - br_token.opr.mbcset = mbcset; - dfa->has_mb_node = 1; - new_idx = re_dfa_add_node (dfa, br_token, 0); - mbc_tree = create_tree (NULL, NULL, 0, new_idx); - if (BE (new_idx == -1 || mbc_tree == NULL, 0)) - goto build_word_op_espace; - /* Then join them by ALT node. */ - alt_token.type = OP_ALT; - new_idx = re_dfa_add_node (dfa, alt_token, 0); - tree = create_tree (tree, mbc_tree, 0, new_idx); - if (BE (new_idx != -1 && mbc_tree != NULL, 1)) - return tree; - } - else - { - free_charset (mbcset); - return tree; - } -#else /* not RE_ENABLE_I18N */ - return tree; -#endif /* not RE_ENABLE_I18N */ - - build_word_op_espace: - re_free (sbcset); -#ifdef RE_ENABLE_I18N - free_charset (mbcset); -#endif /* RE_ENABLE_I18N */ - *err = REG_ESPACE; - return NULL; -} - -/* This is intended for the expressions like "a{1,3}". - Fetch a number from `input', and return the number. - Return -1, if the number field is empty like "{,1}". - Return -2, If an error is occured. */ - -static int -fetch_number (input, token, syntax) - re_string_t *input; - re_token_t *token; - reg_syntax_t syntax; -{ - int num = -1; - unsigned char c; - while (1) - { - *token = fetch_token (input, syntax); - c = token->opr.c; - if (BE (token->type == END_OF_RE, 0)) - return -2; - if (token->type == OP_CLOSE_DUP_NUM || c == ',') - break; - num = ((token->type != CHARACTER || c < '0' || '9' < c || num == -2) - ? -2 : ((num == -1) ? c - '0' : num * 10 + c - '0')); - num = (num > RE_DUP_MAX) ? -2 : num; - } - return num; -} - -#ifdef RE_ENABLE_I18N -static void -free_charset (re_charset_t *cset) -{ - re_free (cset->mbchars); -# ifdef _LIBC - re_free (cset->coll_syms); - re_free (cset->equiv_classes); - re_free (cset->range_starts); - re_free (cset->range_ends); -# endif - re_free (cset->char_classes); - re_free (cset); -} -#endif /* RE_ENABLE_I18N */ - -/* Functions for binary tree operation. */ - -/* Create a node of tree. - Note: This function automatically free left and right if malloc fails. */ - -static bin_tree_t * -create_tree (left, right, type, index) - bin_tree_t *left; - bin_tree_t *right; - re_token_type_t type; - int index; -{ - bin_tree_t *tree; - tree = re_malloc (bin_tree_t, 1); - if (BE (tree == NULL, 0)) - { - free_bin_tree (left); - free_bin_tree (right); - return NULL; - } - tree->parent = NULL; - tree->left = left; - tree->right = right; - tree->type = type; - tree->node_idx = index; - tree->first = -1; - tree->next = -1; - re_node_set_init_empty (&tree->eclosure); - - if (left != NULL) - left->parent = tree; - if (right != NULL) - right->parent = tree; - return tree; -} - -/* Free the sub tree pointed by TREE. */ - -static void -free_bin_tree (tree) - bin_tree_t *tree; -{ - if (tree == NULL) - return; - /*re_node_set_free (&tree->eclosure);*/ - free_bin_tree (tree->left); - free_bin_tree (tree->right); - re_free (tree); -} - -/* Duplicate the node SRC, and return new node. */ - -static bin_tree_t * -duplicate_tree (src, dfa) - const bin_tree_t *src; - re_dfa_t *dfa; -{ - bin_tree_t *left = NULL, *right = NULL, *new_tree; - int new_node_idx; - /* Since node indies must be according to Post-order of the tree, - we must duplicate the left at first. */ - if (src->left != NULL) - { - left = duplicate_tree (src->left, dfa); - if (left == NULL) - return NULL; - } - - /* Secondaly, duplicate the right. */ - if (src->right != NULL) - { - right = duplicate_tree (src->right, dfa); - if (right == NULL) - { - free_bin_tree (left); - return NULL; - } - } - - /* At last, duplicate itself. */ - if (src->type == NON_TYPE) - { - new_node_idx = re_dfa_add_node (dfa, dfa->nodes[src->node_idx], 0); - dfa->nodes[new_node_idx].duplicated = 1; - if (BE (new_node_idx == -1, 0)) - { - free_bin_tree (left); - free_bin_tree (right); - return NULL; - } - } - else - new_node_idx = src->type; - - new_tree = create_tree (left, right, src->type, new_node_idx); - if (BE (new_tree == NULL, 0)) - { - free_bin_tree (left); - free_bin_tree (right); - } - return new_tree; -} diff --git a/util/regex.c b/util/regex.c deleted file mode 100644 index 34d412002..000000000 --- a/util/regex.c +++ /dev/null @@ -1,62 +0,0 @@ -/* Extended regular expression matching and search library. - Copyright (C) 2002 Free Software Foundation, Inc. - This file is part of the GNU C Library. - Contributed by Isamu Hasegawa <[email protected]>. - - The GNU C Library 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. - - The GNU C Library 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 the GNU C Library; if not, write to the Free - Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA - 02110-1301 USA. */ - -#ifdef _LIBC -/* We have to keep the namespace clean. */ -# define regfree(preg) __regfree (preg) -# define regexec(pr, st, nm, pm, ef) __regexec (pr, st, nm, pm, ef) -# define regcomp(preg, pattern, cflags) __regcomp (preg, pattern, cflags) -# define regerror(errcode, preg, errbuf, errbuf_size) \ - __regerror(errcode, preg, errbuf, errbuf_size) -# define re_set_registers(bu, re, nu, st, en) \ - __re_set_registers (bu, re, nu, st, en) -# define re_match_2(bufp, string1, size1, string2, size2, pos, regs, stop) \ - __re_match_2 (bufp, string1, size1, string2, size2, pos, regs, stop) -# define re_match(bufp, string, size, pos, regs) \ - __re_match (bufp, string, size, pos, regs) -# define re_search(bufp, string, size, startpos, range, regs) \ - __re_search (bufp, string, size, startpos, range, regs) -# define re_compile_pattern(pattern, length, bufp) \ - __re_compile_pattern (pattern, length, bufp) -# define re_set_syntax(syntax) __re_set_syntax (syntax) -# define re_search_2(bufp, st1, s1, st2, s2, startpos, range, regs, stop) \ - __re_search_2 (bufp, st1, s1, st2, s2, startpos, range, regs, stop) -# define re_compile_fastmap(bufp) __re_compile_fastmap (bufp) -#endif - -#if _LIBC || __GNUC__ >= 3 -# define BE(expr, val) __builtin_expect (expr, val) -#else -# define BE(expr, val) (expr) -# define inline -#endif - -#include "regcomp.c" -#include "regexec.c" -#include "regex_internal.c" - -/* Binary backward compatibility. */ -#if _LIBC -# include <shlib-compat.h> -# if SHLIB_COMPAT (libc, GLIBC_2_0, GLIBC_2_3) -link_warning (re_max_failures, "the 're_max_failures' variable is obsolete and will go away.") -int re_max_failures = 2000; -# endif -#endif diff --git a/util/regex_internal.c b/util/regex_internal.c deleted file mode 100644 index 0f8b897b1..000000000 --- a/util/regex_internal.c +++ /dev/null @@ -1,1229 +0,0 @@ -/* Extended regular expression matching and search library. - Copyright (C) 2002 Free Software Foundation, Inc. - This file is part of the GNU C Library. - Contributed by Isamu Hasegawa <[email protected]>. - - The GNU C Library 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. - - The GNU C Library 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 the GNU C Library; if not, write to the Free - Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA - 02110-1301 USA. */ - -#include <assert.h> -#include <ctype.h> -#include <limits.h> -#include <stdio.h> -#include <stdlib.h> -#include <string.h> - -#if defined HAVE_WCHAR_H || defined _LIBC -# include <wchar.h> -#endif /* HAVE_WCHAR_H || _LIBC */ -#if defined HAVE_WCTYPE_H || defined _LIBC -# include <wctype.h> -#endif /* HAVE_WCTYPE_H || _LIBC */ - -#ifdef _LIBC -# ifndef _RE_DEFINE_LOCALE_FUNCTIONS -# define _RE_DEFINE_LOCALE_FUNCTIONS 1 -# include <locale/localeinfo.h> -# include <locale/elem-hash.h> -# include <locale/coll-lookup.h> -# endif -#endif - -/* This is for other GNU distributions with internationalized messages. */ -#if HAVE_LIBINTL_H || defined _LIBC -# include <libintl.h> -# ifdef _LIBC -# undef gettext -# define gettext(msgid) \ - INTUSE(__dcgettext) (_libc_intl_domainname_internal, msgid, LC_MESSAGES) -# endif -#else -# define gettext(msgid) (msgid) -#endif - -#ifndef gettext_noop -/* This define is so xgettext can find the internationalizable - strings. */ -# define gettext_noop(String) String -#endif - -#include "_regex.h" /* gnupg */ -#include "regex_internal.h" - -static void re_string_construct_common (const char *str, int len, - re_string_t *pstr, - RE_TRANSLATE_TYPE trans, int icase); -#ifdef RE_ENABLE_I18N -static int re_string_skip_chars (re_string_t *pstr, int new_raw_idx); -#endif /* RE_ENABLE_I18N */ -static re_dfastate_t *create_newstate_common (re_dfa_t *dfa, - const re_node_set *nodes, - unsigned int hash); -static reg_errcode_t register_state (re_dfa_t *dfa, re_dfastate_t *newstate, - unsigned int hash); -static re_dfastate_t *create_ci_newstate (re_dfa_t *dfa, - const re_node_set *nodes, - unsigned int hash); -static re_dfastate_t *create_cd_newstate (re_dfa_t *dfa, - const re_node_set *nodes, - unsigned int context, - unsigned int hash); -static unsigned int inline calc_state_hash (const re_node_set *nodes, - unsigned int context); - -/* Functions for string operation. */ - -/* This function allocate the buffers. It is necessary to call - re_string_reconstruct before using the object. */ - -static reg_errcode_t -re_string_allocate (pstr, str, len, init_len, trans, icase) - re_string_t *pstr; - const char *str; - int len, init_len, icase; - RE_TRANSLATE_TYPE trans; -{ - reg_errcode_t ret; - int init_buf_len = (len + 1 < init_len) ? len + 1: init_len; - re_string_construct_common (str, len, pstr, trans, icase); - pstr->stop = pstr->len; - - ret = re_string_realloc_buffers (pstr, init_buf_len); - if (BE (ret != REG_NOERROR, 0)) - return ret; - - pstr->mbs_case = (MBS_CASE_ALLOCATED (pstr) ? pstr->mbs_case - : (unsigned char *) str); - pstr->mbs = MBS_ALLOCATED (pstr) ? pstr->mbs : pstr->mbs_case; - pstr->valid_len = (MBS_CASE_ALLOCATED (pstr) || MBS_ALLOCATED (pstr) - || MB_CUR_MAX > 1) ? pstr->valid_len : len; - return REG_NOERROR; -} - -/* This function allocate the buffers, and initialize them. */ - -static reg_errcode_t -re_string_construct (pstr, str, len, trans, icase) - re_string_t *pstr; - const char *str; - int len, icase; - RE_TRANSLATE_TYPE trans; -{ - reg_errcode_t ret; - re_string_construct_common (str, len, pstr, trans, icase); - pstr->stop = pstr->len; - /* Set 0 so that this function can initialize whole buffers. */ - pstr->valid_len = 0; - - if (len > 0) - { - ret = re_string_realloc_buffers (pstr, len + 1); - if (BE (ret != REG_NOERROR, 0)) - return ret; - } - pstr->mbs_case = (MBS_CASE_ALLOCATED (pstr) ? pstr->mbs_case - : (unsigned char *) str); - pstr->mbs = MBS_ALLOCATED (pstr) ? pstr->mbs : pstr->mbs_case; - - if (icase) - { -#ifdef RE_ENABLE_I18N - if (MB_CUR_MAX > 1) - build_wcs_upper_buffer (pstr); - else -#endif /* RE_ENABLE_I18N */ - build_upper_buffer (pstr); - } - else - { -#ifdef RE_ENABLE_I18N - if (MB_CUR_MAX > 1) - build_wcs_buffer (pstr); - else -#endif /* RE_ENABLE_I18N */ - { - if (trans != NULL) - re_string_translate_buffer (pstr); - else - pstr->valid_len = len; - } - } - - /* Initialized whole buffers, then valid_len == bufs_len. */ - pstr->valid_len = pstr->bufs_len; - return REG_NOERROR; -} - -/* Helper functions for re_string_allocate, and re_string_construct. */ - -static reg_errcode_t -re_string_realloc_buffers (pstr, new_buf_len) - re_string_t *pstr; - int new_buf_len; -{ -#ifdef RE_ENABLE_I18N - if (MB_CUR_MAX > 1) - { - pstr->wcs = re_realloc (pstr->wcs, wint_t, new_buf_len); - if (BE (pstr->wcs == NULL, 0)) - return REG_ESPACE; - } -#endif /* RE_ENABLE_I18N */ - if (MBS_ALLOCATED (pstr)) - { - pstr->mbs = re_realloc (pstr->mbs, unsigned char, new_buf_len); - if (BE (pstr->mbs == NULL, 0)) - return REG_ESPACE; - } - if (MBS_CASE_ALLOCATED (pstr)) - { - pstr->mbs_case = re_realloc (pstr->mbs_case, unsigned char, new_buf_len); - if (BE (pstr->mbs_case == NULL, 0)) - return REG_ESPACE; - if (!MBS_ALLOCATED (pstr)) - pstr->mbs = pstr->mbs_case; - } - pstr->bufs_len = new_buf_len; - return REG_NOERROR; -} - - -static void -re_string_construct_common (str, len, pstr, trans, icase) - const char *str; - int len; - re_string_t *pstr; - RE_TRANSLATE_TYPE trans; - int icase; -{ - memset (pstr, '\0', sizeof (re_string_t)); - pstr->raw_mbs = (const unsigned char *) str; - pstr->len = len; - pstr->trans = trans; - pstr->icase = icase ? 1 : 0; -} - -#ifdef RE_ENABLE_I18N - -/* Build wide character buffer PSTR->WCS. - If the byte sequence of the string are: - <mb1>(0), <mb1>(1), <mb2>(0), <mb2>(1), <sb3> - Then wide character buffer will be: - <wc1> , WEOF , <wc2> , WEOF , <wc3> - We use WEOF for padding, they indicate that the position isn't - a first byte of a multibyte character. - - Note that this function assumes PSTR->VALID_LEN elements are already - built and starts from PSTR->VALID_LEN. */ - -static void -build_wcs_buffer (pstr) - re_string_t *pstr; -{ - mbstate_t prev_st; - int byte_idx, end_idx, mbclen, remain_len; - /* Build the buffers from pstr->valid_len to either pstr->len or - pstr->bufs_len. */ - end_idx = (pstr->bufs_len > pstr->len)? pstr->len : pstr->bufs_len; - for (byte_idx = pstr->valid_len; byte_idx < end_idx;) - { - wchar_t wc; - remain_len = end_idx - byte_idx; - prev_st = pstr->cur_state; - mbclen = mbrtowc (&wc, ((const char *) pstr->raw_mbs + pstr->raw_mbs_idx - + byte_idx), remain_len, &pstr->cur_state); - if (BE (mbclen == (size_t) -2, 0)) - { - /* The buffer doesn't have enough space, finish to build. */ - pstr->cur_state = prev_st; - break; - } - else if (BE (mbclen == (size_t) -1 || mbclen == 0, 0)) - { - /* We treat these cases as a singlebyte character. */ - mbclen = 1; - wc = (wchar_t) pstr->raw_mbs[pstr->raw_mbs_idx + byte_idx]; - pstr->cur_state = prev_st; - } - - /* Apply the translateion if we need. */ - if (pstr->trans != NULL && mbclen == 1) - { - int ch = pstr->trans[pstr->raw_mbs[pstr->raw_mbs_idx + byte_idx]]; - pstr->mbs_case[byte_idx] = ch; - } - /* Write wide character and padding. */ - pstr->wcs[byte_idx++] = wc; - /* Write paddings. */ - for (remain_len = byte_idx + mbclen - 1; byte_idx < remain_len ;) - pstr->wcs[byte_idx++] = WEOF; - } - pstr->valid_len = byte_idx; -} - -/* Build wide character buffer PSTR->WCS like build_wcs_buffer, - but for REG_ICASE. */ - -static void -build_wcs_upper_buffer (pstr) - re_string_t *pstr; -{ - mbstate_t prev_st; - int byte_idx, end_idx, mbclen, remain_len; - /* Build the buffers from pstr->valid_len to either pstr->len or - pstr->bufs_len. */ - end_idx = (pstr->bufs_len > pstr->len)? pstr->len : pstr->bufs_len; - for (byte_idx = pstr->valid_len; byte_idx < end_idx;) - { - wchar_t wc; - remain_len = end_idx - byte_idx; - prev_st = pstr->cur_state; - mbclen = mbrtowc (&wc, ((const char *) pstr->raw_mbs + pstr->raw_mbs_idx - + byte_idx), remain_len, &pstr->cur_state); - if (BE (mbclen == (size_t) -2, 0)) - { - /* The buffer doesn't have enough space, finish to build. */ - pstr->cur_state = prev_st; - break; - } - else if (mbclen == 1 || mbclen == (size_t) -1 || mbclen == 0) - { - /* In case of a singlebyte character. */ - int ch = pstr->raw_mbs[pstr->raw_mbs_idx + byte_idx]; - /* Apply the translateion if we need. */ - if (pstr->trans != NULL && mbclen == 1) - { - ch = pstr->trans[ch]; - pstr->mbs_case[byte_idx] = ch; - } - pstr->wcs[byte_idx] = iswlower (wc) ? toupper (wc) : wc; - pstr->mbs[byte_idx++] = islower (ch) ? toupper (ch) : ch; - if (BE (mbclen == (size_t) -1, 0)) - pstr->cur_state = prev_st; - } - else /* mbclen > 1 */ - { - if (iswlower (wc)) - wcrtomb ((char *) pstr->mbs + byte_idx, towupper (wc), &prev_st); - else - memcpy (pstr->mbs + byte_idx, - pstr->raw_mbs + pstr->raw_mbs_idx + byte_idx, mbclen); - pstr->wcs[byte_idx++] = iswlower (wc) ? toupper (wc) : wc; - /* Write paddings. */ - for (remain_len = byte_idx + mbclen - 1; byte_idx < remain_len ;) - pstr->wcs[byte_idx++] = WEOF; - } - } - pstr->valid_len = byte_idx; -} - -/* Skip characters until the index becomes greater than NEW_RAW_IDX. - Return the index. */ - -static int -re_string_skip_chars (pstr, new_raw_idx) - re_string_t *pstr; - int new_raw_idx; -{ - mbstate_t prev_st; - int rawbuf_idx, mbclen; - - /* Skip the characters which are not necessary to check. */ - for (rawbuf_idx = pstr->raw_mbs_idx + pstr->valid_len; - rawbuf_idx < new_raw_idx;) - { - int remain_len = pstr->len - rawbuf_idx; - prev_st = pstr->cur_state; - mbclen = mbrlen ((const char *) pstr->raw_mbs + rawbuf_idx, remain_len, - &pstr->cur_state); - if (BE (mbclen == (size_t) -2 || mbclen == (size_t) -1 || mbclen == 0, 0)) - { - /* We treat these cases as a singlebyte character. */ - mbclen = 1; - pstr->cur_state = prev_st; - } - /* Then proceed the next character. */ - rawbuf_idx += mbclen; - } - return rawbuf_idx; -} -#endif /* RE_ENABLE_I18N */ - -/* Build the buffer PSTR->MBS, and apply the translation if we need. - This function is used in case of REG_ICASE. */ - -static void -build_upper_buffer (pstr) - re_string_t *pstr; -{ - int char_idx, end_idx; - end_idx = (pstr->bufs_len > pstr->len) ? pstr->len : pstr->bufs_len; - - for (char_idx = pstr->valid_len; char_idx < end_idx; ++char_idx) - { - int ch = pstr->raw_mbs[pstr->raw_mbs_idx + char_idx]; - if (pstr->trans != NULL) - { - ch = pstr->trans[ch]; - pstr->mbs_case[char_idx] = ch; - } - if (islower (ch)) - pstr->mbs[char_idx] = toupper (ch); - else - pstr->mbs[char_idx] = ch; - } - pstr->valid_len = char_idx; -} - -/* Apply TRANS to the buffer in PSTR. */ - -static void -re_string_translate_buffer (pstr) - re_string_t *pstr; -{ - int buf_idx, end_idx; - end_idx = (pstr->bufs_len > pstr->len) ? pstr->len : pstr->bufs_len; - - for (buf_idx = pstr->valid_len; buf_idx < end_idx; ++buf_idx) - { - int ch = pstr->raw_mbs[pstr->raw_mbs_idx + buf_idx]; - pstr->mbs_case[buf_idx] = pstr->trans[ch]; - } - - pstr->valid_len = buf_idx; -} - -/* This function re-construct the buffers. - Concretely, convert to wide character in case of MB_CUR_MAX > 1, - convert to upper case in case of REG_ICASE, apply translation. */ - -static reg_errcode_t -re_string_reconstruct (pstr, idx, eflags, newline) - re_string_t *pstr; - int idx, eflags, newline; -{ - int offset = idx - pstr->raw_mbs_idx; - if (offset < 0) - { - /* Reset buffer. */ -#ifdef RE_ENABLE_I18N - if (MB_CUR_MAX > 1) - memset (&pstr->cur_state, '\0', sizeof (mbstate_t)); -#endif /* RE_ENABLE_I18N */ - pstr->len += pstr->raw_mbs_idx; - pstr->stop += pstr->raw_mbs_idx; - pstr->valid_len = pstr->raw_mbs_idx = 0; - pstr->tip_context = ((eflags & REG_NOTBOL) ? CONTEXT_BEGBUF - : CONTEXT_NEWLINE | CONTEXT_BEGBUF); - if (!MBS_CASE_ALLOCATED (pstr)) - pstr->mbs_case = (unsigned char *) pstr->raw_mbs; - if (!MBS_ALLOCATED (pstr) && !MBS_CASE_ALLOCATED (pstr)) - pstr->mbs = (unsigned char *) pstr->raw_mbs; - offset = idx; - } - - if (offset != 0) - { - pstr->tip_context = re_string_context_at (pstr, offset - 1, eflags, - newline); - /* Are the characters which are already checked remain? */ - if (offset < pstr->valid_len) - { - /* Yes, move them to the front of the buffer. */ -#ifdef RE_ENABLE_I18N - if (MB_CUR_MAX > 1) - memmove (pstr->wcs, pstr->wcs + offset, - (pstr->valid_len - offset) * sizeof (wint_t)); -#endif /* RE_ENABLE_I18N */ - if (MBS_ALLOCATED (pstr)) - memmove (pstr->mbs, pstr->mbs + offset, - pstr->valid_len - offset); - if (MBS_CASE_ALLOCATED (pstr)) - memmove (pstr->mbs_case, pstr->mbs_case + offset, - pstr->valid_len - offset); - pstr->valid_len -= offset; -#if DEBUG - assert (pstr->valid_len > 0); -#endif - } - else - { - /* No, skip all characters until IDX. */ - pstr->valid_len = 0; -#ifdef RE_ENABLE_I18N - if (MB_CUR_MAX > 1) - { - int wcs_idx; - pstr->valid_len = re_string_skip_chars (pstr, idx) - idx; - for (wcs_idx = 0; wcs_idx < pstr->valid_len; ++wcs_idx) - pstr->wcs[wcs_idx] = WEOF; - } -#endif /* RE_ENABLE_I18N */ - } - if (!MBS_CASE_ALLOCATED (pstr)) - { - pstr->mbs_case += offset; - /* In case of !MBS_ALLOCATED && !MBS_CASE_ALLOCATED. */ - if (!MBS_ALLOCATED (pstr)) - pstr->mbs += offset; - } - } - pstr->raw_mbs_idx = idx; - pstr->len -= offset; - pstr->stop -= offset; - - /* Then build the buffers. */ -#ifdef RE_ENABLE_I18N - if (MB_CUR_MAX > 1) - { - if (pstr->icase) - build_wcs_upper_buffer (pstr); - else - build_wcs_buffer (pstr); - } - else -#endif /* RE_ENABLE_I18N */ - { - if (pstr->icase) - build_upper_buffer (pstr); - else if (pstr->trans != NULL) - re_string_translate_buffer (pstr); - } - pstr->cur_idx = 0; - - return REG_NOERROR; -} - -static void -re_string_destruct (pstr) - re_string_t *pstr; -{ -#ifdef RE_ENABLE_I18N - re_free (pstr->wcs); -#endif /* RE_ENABLE_I18N */ - if (MBS_ALLOCATED (pstr)) - re_free (pstr->mbs); - if (MBS_CASE_ALLOCATED (pstr)) - re_free (pstr->mbs_case); -} - -/* Return the context at IDX in INPUT. */ - -static unsigned int -re_string_context_at (input, idx, eflags, newline_anchor) - const re_string_t *input; - int idx, eflags, newline_anchor; -{ - int c; - if (idx < 0 || idx == input->len) - { - if (idx < 0) - /* In this case, we use the value stored in input->tip_context, - since we can't know the character in input->mbs[-1] here. */ - return input->tip_context; - else /* (idx == input->len) */ - return ((eflags & REG_NOTEOL) ? CONTEXT_ENDBUF - : CONTEXT_NEWLINE | CONTEXT_ENDBUF); - } - c = re_string_byte_at (input, idx); - if (IS_WORD_CHAR (c)) - return CONTEXT_WORD; - return (newline_anchor && IS_NEWLINE (c)) ? CONTEXT_NEWLINE : 0; -} - -/* Functions for set operation. */ - -static reg_errcode_t -re_node_set_alloc (set, size) - re_node_set *set; - int size; -{ - set->alloc = size; - set->nelem = 0; - set->elems = re_malloc (int, size); - if (BE (set->elems == NULL, 0)) - return REG_ESPACE; - return REG_NOERROR; -} - -static reg_errcode_t -re_node_set_init_1 (set, elem) - re_node_set *set; - int elem; -{ - set->alloc = 1; - set->nelem = 1; - set->elems = re_malloc (int, 1); - if (BE (set->elems == NULL, 0)) - return REG_ESPACE; - set->elems[0] = elem; - return REG_NOERROR; -} - -static reg_errcode_t -re_node_set_init_2 (set, elem1, elem2) - re_node_set *set; - int elem1, elem2; -{ - set->alloc = 2; - set->elems = re_malloc (int, 2); - if (BE (set->elems == NULL, 0)) - return REG_ESPACE; - if (elem1 == elem2) - { - set->nelem = 1; - set->elems[0] = elem1; - } - else - { - set->nelem = 2; - if (elem1 < elem2) - { - set->elems[0] = elem1; - set->elems[1] = elem2; - } - else - { - set->elems[0] = elem2; - set->elems[1] = elem1; - } - } - return REG_NOERROR; -} - -static reg_errcode_t -re_node_set_init_copy (dest, src) - re_node_set *dest; - const re_node_set *src; -{ - dest->nelem = src->nelem; - if (src->nelem > 0) - { - dest->alloc = dest->nelem; - dest->elems = re_malloc (int, dest->alloc); - if (BE (dest->elems == NULL, 0)) - return REG_ESPACE; - memcpy (dest->elems, src->elems, src->nelem * sizeof (int)); - } - else - re_node_set_init_empty (dest); - return REG_NOERROR; -} - -/* Calculate the intersection of the sets SRC1 and SRC2. And merge it to - DEST. Return value indicate the error code or REG_NOERROR if succeeded. - Note: We assume dest->elems is NULL, when dest->alloc is 0. */ - -static reg_errcode_t -re_node_set_add_intersect (dest, src1, src2) - re_node_set *dest; - const re_node_set *src1, *src2; -{ - int i1, i2, id; - if (src1->nelem > 0 && src2->nelem > 0) - { - if (src1->nelem + src2->nelem + dest->nelem > dest->alloc) - { - dest->alloc = src1->nelem + src2->nelem + dest->nelem; - dest->elems = re_realloc (dest->elems, int, dest->alloc); - if (BE (dest->elems == NULL, 0)) - return REG_ESPACE; - } - } - else - return REG_NOERROR; - - for (i1 = i2 = id = 0 ; i1 < src1->nelem && i2 < src2->nelem ;) - { - if (src1->elems[i1] > src2->elems[i2]) - { - ++i2; - continue; - } - if (src1->elems[i1] == src2->elems[i2]) - { - while (id < dest->nelem && dest->elems[id] < src2->elems[i2]) - ++id; - if (id < dest->nelem && dest->elems[id] == src2->elems[i2]) - ++id; - else - { - memmove (dest->elems + id + 1, dest->elems + id, - sizeof (int) * (dest->nelem - id)); - dest->elems[id++] = src2->elems[i2++]; - ++dest->nelem; - } - } - ++i1; - } - return REG_NOERROR; -} - -/* Calculate the union set of the sets SRC1 and SRC2. And store it to - DEST. Return value indicate the error code or REG_NOERROR if succeeded. */ - -static reg_errcode_t -re_node_set_init_union (dest, src1, src2) - re_node_set *dest; - const re_node_set *src1, *src2; -{ - int i1, i2, id; - if (src1 != NULL && src1->nelem > 0 && src2 != NULL && src2->nelem > 0) - { - dest->alloc = src1->nelem + src2->nelem; - dest->elems = re_malloc (int, dest->alloc); - if (BE (dest->elems == NULL, 0)) - return REG_ESPACE; - } - else - { - if (src1 != NULL && src1->nelem > 0) - return re_node_set_init_copy (dest, src1); - else if (src2 != NULL && src2->nelem > 0) - return re_node_set_init_copy (dest, src2); - else - re_node_set_init_empty (dest); - return REG_NOERROR; - } - for (i1 = i2 = id = 0 ; i1 < src1->nelem && i2 < src2->nelem ;) - { - if (src1->elems[i1] > src2->elems[i2]) - { - dest->elems[id++] = src2->elems[i2++]; - continue; - } - if (src1->elems[i1] == src2->elems[i2]) - ++i2; - dest->elems[id++] = src1->elems[i1++]; - } - if (i1 < src1->nelem) - { - memcpy (dest->elems + id, src1->elems + i1, - (src1->nelem - i1) * sizeof (int)); - id += src1->nelem - i1; - } - else if (i2 < src2->nelem) - { - memcpy (dest->elems + id, src2->elems + i2, - (src2->nelem - i2) * sizeof (int)); - id += src2->nelem - i2; - } - dest->nelem = id; - return REG_NOERROR; -} - -/* Calculate the union set of the sets DEST and SRC. And store it to - DEST. Return value indicate the error code or REG_NOERROR if succeeded. */ - -static reg_errcode_t -re_node_set_merge (dest, src) - re_node_set *dest; - const re_node_set *src; -{ - int si, di; - if (src == NULL || src->nelem == 0) - return REG_NOERROR; - if (dest->alloc < src->nelem + dest->nelem) - { - dest->alloc = 2 * (src->nelem + dest->alloc); - dest->elems = re_realloc (dest->elems, int, dest->alloc); - if (BE (dest->elems == NULL, 0)) - return REG_ESPACE; - } - - for (si = 0, di = 0 ; si < src->nelem && di < dest->nelem ;) - { - int cp_from, ncp, mid, right, src_elem = src->elems[si]; - /* Binary search the spot we will add the new element. */ - right = dest->nelem; - while (di < right) - { - mid = (di + right) / 2; - if (dest->elems[mid] < src_elem) - di = mid + 1; - else - right = mid; - } - if (di >= dest->nelem) - break; - - if (dest->elems[di] == src_elem) - { - /* Skip since, DEST already has the element. */ - ++di; - ++si; - continue; - } - - /* Skip the src elements which are less than dest->elems[di]. */ - cp_from = si; - while (si < src->nelem && src->elems[si] < dest->elems[di]) - ++si; - /* Copy these src elements. */ - ncp = si - cp_from; - memmove (dest->elems + di + ncp, dest->elems + di, - sizeof (int) * (dest->nelem - di)); - memcpy (dest->elems + di, src->elems + cp_from, - sizeof (int) * ncp); - /* Update counters. */ - di += ncp; - dest->nelem += ncp; - } - - /* Copy remaining src elements. */ - if (si < src->nelem) - { - memcpy (dest->elems + di, src->elems + si, - sizeof (int) * (src->nelem - si)); - dest->nelem += src->nelem - si; - } - return REG_NOERROR; -} - -/* Insert the new element ELEM to the re_node_set* SET. - return 0 if SET already has ELEM, - return -1 if an error is occured, return 1 otherwise. */ - -static int -re_node_set_insert (set, elem) - re_node_set *set; - int elem; -{ - int idx, right, mid; - /* In case of the set is empty. */ - if (set->elems == NULL || set->alloc == 0) - { - if (BE (re_node_set_init_1 (set, elem) == REG_NOERROR, 1)) - return 1; - else - return -1; - } - - /* Binary search the spot we will add the new element. */ - idx = 0; - right = set->nelem; - while (idx < right) - { - mid = (idx + right) / 2; - if (set->elems[mid] < elem) - idx = mid + 1; - else - right = mid; - } - - /* Realloc if we need. */ - if (set->alloc < set->nelem + 1) - { - int *new_array; - set->alloc = set->alloc * 2; - new_array = re_malloc (int, set->alloc); - if (BE (new_array == NULL, 0)) - return -1; - /* Copy the elements they are followed by the new element. */ - if (idx > 0) - memcpy (new_array, set->elems, sizeof (int) * (idx)); - /* Copy the elements which follows the new element. */ - if (set->nelem - idx > 0) - memcpy (new_array + idx + 1, set->elems + idx, - sizeof (int) * (set->nelem - idx)); - re_free (set->elems); - set->elems = new_array; - } - else - { - /* Move the elements which follows the new element. */ - if (set->nelem - idx > 0) - memmove (set->elems + idx + 1, set->elems + idx, - sizeof (int) * (set->nelem - idx)); - } - /* Insert the new element. */ - set->elems[idx] = elem; - ++set->nelem; - return 1; -} - -/* Compare two node sets SET1 and SET2. - return 1 if SET1 and SET2 are equivalent, retrun 0 otherwise. */ - -static int -re_node_set_compare (set1, set2) - const re_node_set *set1, *set2; -{ - int i; - if (set1 == NULL || set2 == NULL || set1->nelem != set2->nelem) - return 0; - for (i = 0 ; i < set1->nelem ; i++) - if (set1->elems[i] != set2->elems[i]) - return 0; - return 1; -} - -/* Return (idx + 1) if SET contains the element ELEM, return 0 otherwise. */ - -static int -re_node_set_contains (set, elem) - const re_node_set *set; - int elem; -{ - int idx, right, mid; - if (set->nelem <= 0) - return 0; - - /* Binary search the element. */ - idx = 0; - right = set->nelem - 1; - while (idx < right) - { - mid = (idx + right) / 2; - if (set->elems[mid] < elem) - idx = mid + 1; - else - right = mid; - } - return set->elems[idx] == elem ? idx + 1 : 0; -} - -static void -re_node_set_remove_at (set, idx) - re_node_set *set; - int idx; -{ - if (idx < 0 || idx >= set->nelem) - return; - if (idx < set->nelem - 1) - memmove (set->elems + idx, set->elems + idx + 1, - sizeof (int) * (set->nelem - idx - 1)); - --set->nelem; -} - - -/* Add the token TOKEN to dfa->nodes, and return the index of the token. - Or return -1, if an error will be occured. */ - -static int -re_dfa_add_node (dfa, token, mode) - re_dfa_t *dfa; - re_token_t token; - int mode; -{ - if (dfa->nodes_len >= dfa->nodes_alloc) - { - re_token_t *new_array; - dfa->nodes_alloc *= 2; - new_array = re_realloc (dfa->nodes, re_token_t, dfa->nodes_alloc); - if (BE (new_array == NULL, 0)) - return -1; - else - dfa->nodes = new_array; - if (mode) - { - int *new_firsts, *new_nexts; - re_node_set *new_edests, *new_eclosures, *new_inveclosures; - - new_firsts = re_realloc (dfa->firsts, int, dfa->nodes_alloc); - new_nexts = re_realloc (dfa->nexts, int, dfa->nodes_alloc); - new_edests = re_realloc (dfa->edests, re_node_set, dfa->nodes_alloc); - new_eclosures = re_realloc (dfa->eclosures, re_node_set, - dfa->nodes_alloc); - new_inveclosures = re_realloc (dfa->inveclosures, re_node_set, - dfa->nodes_alloc); - if (BE (new_firsts == NULL || new_nexts == NULL || new_edests == NULL - || new_eclosures == NULL || new_inveclosures == NULL, 0)) - return -1; - dfa->firsts = new_firsts; - dfa->nexts = new_nexts; - dfa->edests = new_edests; - dfa->eclosures = new_eclosures; - dfa->inveclosures = new_inveclosures; - } - } - dfa->nodes[dfa->nodes_len] = token; - dfa->nodes[dfa->nodes_len].duplicated = 0; - return dfa->nodes_len++; -} - -static unsigned int inline -calc_state_hash (nodes, context) - const re_node_set *nodes; - unsigned int context; -{ - unsigned int hash = nodes->nelem + context; - int i; - for (i = 0 ; i < nodes->nelem ; i++) - hash += nodes->elems[i]; - return hash; -} - -/* Search for the state whose node_set is equivalent to NODES. - Return the pointer to the state, if we found it in the DFA. - Otherwise create the new one and return it. In case of an error - return NULL and set the error code in ERR. - Note: - We assume NULL as the invalid state, then it is possible that - return value is NULL and ERR is REG_NOERROR. - - We never return non-NULL value in case of any errors, it is for - optimization. */ - -static re_dfastate_t* -re_acquire_state (err, dfa, nodes) - reg_errcode_t *err; - re_dfa_t *dfa; - const re_node_set *nodes; -{ - unsigned int hash; - re_dfastate_t *new_state; - struct re_state_table_entry *spot; - int i; - if (BE (nodes->nelem == 0, 0)) - { - *err = REG_NOERROR; - return NULL; - } - hash = calc_state_hash (nodes, 0); - spot = dfa->state_table + (hash & dfa->state_hash_mask); - - for (i = 0 ; i < spot->num ; i++) - { - re_dfastate_t *state = spot->array[i]; - if (hash != state->hash) - continue; - if (re_node_set_compare (&state->nodes, nodes)) - return state; - } - - /* There are no appropriate state in the dfa, create the new one. */ - new_state = create_ci_newstate (dfa, nodes, hash); - if (BE (new_state != NULL, 1)) - return new_state; - else - { - *err = REG_ESPACE; - return NULL; - } -} - -/* Search for the state whose node_set is equivalent to NODES and - whose context is equivalent to CONTEXT. - Return the pointer to the state, if we found it in the DFA. - Otherwise create the new one and return it. In case of an error - return NULL and set the error code in ERR. - Note: - We assume NULL as the invalid state, then it is possible that - return value is NULL and ERR is REG_NOERROR. - - We never return non-NULL value in case of any errors, it is for - optimization. */ - -static re_dfastate_t* -re_acquire_state_context (err, dfa, nodes, context) - reg_errcode_t *err; - re_dfa_t *dfa; - const re_node_set *nodes; - unsigned int context; -{ - unsigned int hash; - re_dfastate_t *new_state; - struct re_state_table_entry *spot; - int i; - if (nodes->nelem == 0) - { - *err = REG_NOERROR; - return NULL; - } - hash = calc_state_hash (nodes, context); - spot = dfa->state_table + (hash & dfa->state_hash_mask); - - for (i = 0 ; i < spot->num ; i++) - { - re_dfastate_t *state = spot->array[i]; - if (hash != state->hash) - continue; - if (re_node_set_compare (state->entrance_nodes, nodes) - && state->context == context) - return state; - } - /* There are no appropriate state in `dfa', create the new one. */ - new_state = create_cd_newstate (dfa, nodes, context, hash); - if (BE (new_state != NULL, 1)) - return new_state; - else - { - *err = REG_ESPACE; - return NULL; - } -} - -/* Allocate memory for DFA state and initialize common properties. - Return the new state if succeeded, otherwise return NULL. */ - -static re_dfastate_t * -create_newstate_common (dfa, nodes, hash) - re_dfa_t *dfa; - const re_node_set *nodes; - unsigned int hash; -{ - re_dfastate_t *newstate; - newstate = (re_dfastate_t *) calloc (sizeof (re_dfastate_t), 1); - if (BE (newstate == NULL, 0)) - return NULL; - re_node_set_init_copy (&newstate->nodes, nodes); - newstate->trtable = NULL; - newstate->trtable_search = NULL; - newstate->hash = hash; - return newstate; -} - -/* Store the new state NEWSTATE whose hash value is HASH in appropriate - position. Return value indicate the error code if failed. */ - -static reg_errcode_t -register_state (dfa, newstate, hash) - re_dfa_t *dfa; - re_dfastate_t *newstate; - unsigned int hash; -{ - struct re_state_table_entry *spot; - spot = dfa->state_table + (hash & dfa->state_hash_mask); - - if (spot->alloc <= spot->num) - { - spot->alloc = 2 * spot->num + 2; - spot->array = re_realloc (spot->array, re_dfastate_t *, spot->alloc); - if (BE (spot->array == NULL, 0)) - return REG_ESPACE; - } - spot->array[spot->num++] = newstate; - return REG_NOERROR; -} - -/* Create the new state which is independ of contexts. - Return the new state if succeeded, otherwise return NULL. */ - -static re_dfastate_t * -create_ci_newstate (dfa, nodes, hash) - re_dfa_t *dfa; - const re_node_set *nodes; - unsigned int hash; -{ - int i; - reg_errcode_t err; - re_dfastate_t *newstate; - newstate = create_newstate_common (dfa, nodes, hash); - if (BE (newstate == NULL, 0)) - return NULL; - newstate->entrance_nodes = &newstate->nodes; - - for (i = 0 ; i < nodes->nelem ; i++) - { - re_token_t *node = dfa->nodes + nodes->elems[i]; - re_token_type_t type = node->type; - if (type == CHARACTER) - continue; - - /* If the state has the halt node, the state is a halt state. */ - else if (type == END_OF_RE) - newstate->halt = 1; -#ifdef RE_ENABLE_I18N - else if (type == COMPLEX_BRACKET - || (type == OP_PERIOD && MB_CUR_MAX > 1)) - newstate->accept_mb = 1; -#endif /* RE_ENABLE_I18N */ - else if (type == OP_BACK_REF) - newstate->has_backref = 1; - else if (type == ANCHOR || OP_CONTEXT_NODE) - { - newstate->has_constraint = 1; - if (type == OP_CONTEXT_NODE - && dfa->nodes[node->opr.ctx_info->entity].type == END_OF_RE) - newstate->halt = 1; - } - } - err = register_state (dfa, newstate, hash); - return (err != REG_NOERROR) ? NULL : newstate; -} - -/* Create the new state which is depend on the context CONTEXT. - Return the new state if succeeded, otherwise return NULL. */ - -static re_dfastate_t * -create_cd_newstate (dfa, nodes, context, hash) - re_dfa_t *dfa; - const re_node_set *nodes; - unsigned int context, hash; -{ - int i, nctx_nodes = 0; - reg_errcode_t err; - re_dfastate_t *newstate; - - newstate = create_newstate_common (dfa, nodes, hash); - if (BE (newstate == NULL, 0)) - return NULL; - newstate->context = context; - newstate->entrance_nodes = &newstate->nodes; - - for (i = 0 ; i < nodes->nelem ; i++) - { - unsigned int constraint = 0; - re_token_t *node = dfa->nodes + nodes->elems[i]; - re_token_type_t type = node->type; - if (type == CHARACTER) - continue; - - /* If the state has the halt node, the state is a halt state. */ - else if (type == END_OF_RE) - newstate->halt = 1; -#ifdef RE_ENABLE_I18N - else if (type == COMPLEX_BRACKET - || (type == OP_PERIOD && MB_CUR_MAX > 1)) - newstate->accept_mb = 1; -#endif /* RE_ENABLE_I18N */ - else if (type == OP_BACK_REF) - newstate->has_backref = 1; - else if (type == ANCHOR) - constraint = node->opr.ctx_type; - else if (type == OP_CONTEXT_NODE) - { - re_token_type_t ctype = dfa->nodes[node->opr.ctx_info->entity].type; - constraint = node->constraint; - if (ctype == END_OF_RE) - newstate->halt = 1; - else if (ctype == OP_BACK_REF) - newstate->has_backref = 1; -#ifdef RE_ENABLE_I18N - else if (ctype == COMPLEX_BRACKET - || (type == OP_PERIOD && MB_CUR_MAX > 1)) - newstate->accept_mb = 1; -#endif /* RE_ENABLE_I18N */ - } - - if (constraint) - { - if (newstate->entrance_nodes == &newstate->nodes) - { - newstate->entrance_nodes = re_malloc (re_node_set, 1); - if (BE (newstate->entrance_nodes == NULL, 0)) - return NULL; - re_node_set_init_copy (newstate->entrance_nodes, nodes); - nctx_nodes = 0; - newstate->has_constraint = 1; - } - - if (NOT_SATISFY_PREV_CONSTRAINT (constraint,context)) - { - re_node_set_remove_at (&newstate->nodes, i - nctx_nodes); - ++nctx_nodes; - } - } - } - err = register_state (dfa, newstate, hash); - return (err != REG_NOERROR) ? NULL : newstate; -} diff --git a/util/regex_internal.h b/util/regex_internal.h deleted file mode 100644 index 679bea11b..000000000 --- a/util/regex_internal.h +++ /dev/null @@ -1,643 +0,0 @@ -/* Extended regular expression matching and search library. - Copyright (C) 2002 Free Software Foundation, Inc. - This file is part of the GNU C Library. - Contributed by Isamu Hasegawa <[email protected]>. - - The GNU C Library 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. - - The GNU C Library 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 the GNU C Library; if not, write to the Free - Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA - 02110-1301 USA. */ - -#ifndef _REGEX_INTERNAL_H -#define _REGEX_INTERNAL_H 1 - -/* Number of bits in a byte. */ -#define BYTE_BITS 8 -/* Number of single byte character. */ -#define SBC_MAX 256 - -#define COLL_ELEM_LEN_MAX 8 - -/* The character which represents newline. */ -#define NEWLINE_CHAR '\n' - -/* Rename to standard API for using out of glibc. */ -#ifndef _LIBC -# define __wctype wctype -# define __iswctype iswctype -# define __btowc btowc -# define __mempcpy memcpy -# define attribute_hidden -#endif /* not _LIBC */ - -extern const char __re_error_msgid[] attribute_hidden; -extern const size_t __re_error_msgid_idx[] attribute_hidden; - -/* Number of bits in an unsinged int. */ -#define UINT_BITS (sizeof (unsigned int) * BYTE_BITS) -/* Number of unsigned int in an bit_set. */ -#define BITSET_UINTS ((SBC_MAX + UINT_BITS - 1) / UINT_BITS) -typedef unsigned int bitset[BITSET_UINTS]; -typedef unsigned int *re_bitset_ptr_t; - -#define bitset_set(set,i) (set[i / UINT_BITS] |= 1 << i % UINT_BITS) -#define bitset_clear(set,i) (set[i / UINT_BITS] &= ~(1 << i % UINT_BITS)) -#define bitset_contain(set,i) (set[i / UINT_BITS] & (1 << i % UINT_BITS)) -#define bitset_empty(set) memset (set, 0, sizeof (unsigned int) * BITSET_UINTS) -#define bitset_set_all(set) \ - memset (set, 255, sizeof (unsigned int) * BITSET_UINTS) -#define bitset_copy(dest,src) \ - memcpy (dest, src, sizeof (unsigned int) * BITSET_UINTS) -static inline void bitset_not (bitset set); -static inline void bitset_merge (bitset dest, const bitset src); -#if 0 /* gnupg */ -static inline void bitset_not_merge (bitset dest, const bitset src); -#endif - -#define PREV_WORD_CONSTRAINT 0x0001 -#define PREV_NOTWORD_CONSTRAINT 0x0002 -#define NEXT_WORD_CONSTRAINT 0x0004 -#define NEXT_NOTWORD_CONSTRAINT 0x0008 -#define PREV_NEWLINE_CONSTRAINT 0x0010 -#define NEXT_NEWLINE_CONSTRAINT 0x0020 -#define PREV_BEGBUF_CONSTRAINT 0x0040 -#define NEXT_ENDBUF_CONSTRAINT 0x0080 -#define DUMMY_CONSTRAINT 0x0100 - -typedef enum -{ - INSIDE_WORD = PREV_WORD_CONSTRAINT | NEXT_WORD_CONSTRAINT, - WORD_FIRST = PREV_NOTWORD_CONSTRAINT | NEXT_WORD_CONSTRAINT, - WORD_LAST = PREV_WORD_CONSTRAINT | NEXT_NOTWORD_CONSTRAINT, - LINE_FIRST = PREV_NEWLINE_CONSTRAINT, - LINE_LAST = NEXT_NEWLINE_CONSTRAINT, - BUF_FIRST = PREV_BEGBUF_CONSTRAINT, - BUF_LAST = NEXT_ENDBUF_CONSTRAINT, - WORD_DELIM = DUMMY_CONSTRAINT -} re_context_type; - -typedef struct -{ - int alloc; - int nelem; - int *elems; -} re_node_set; - -typedef enum -{ - NON_TYPE = 0, - - /* Token type, these are used only by token. */ - OP_OPEN_BRACKET, - OP_CLOSE_BRACKET, - OP_CHARSET_RANGE, - OP_OPEN_DUP_NUM, - OP_CLOSE_DUP_NUM, - OP_NON_MATCH_LIST, - OP_OPEN_COLL_ELEM, - OP_CLOSE_COLL_ELEM, - OP_OPEN_EQUIV_CLASS, - OP_CLOSE_EQUIV_CLASS, - OP_OPEN_CHAR_CLASS, - OP_CLOSE_CHAR_CLASS, - OP_WORD, - OP_NOTWORD, - BACK_SLASH, - - /* Tree type, these are used only by tree. */ - CONCAT, - ALT, - SUBEXP, - SIMPLE_BRACKET, -#ifdef RE_ENABLE_I18N - COMPLEX_BRACKET, -#endif /* RE_ENABLE_I18N */ - - /* Node type, These are used by token, node, tree. */ - OP_OPEN_SUBEXP, - OP_CLOSE_SUBEXP, - OP_PERIOD, - CHARACTER, - END_OF_RE, - OP_ALT, - OP_DUP_ASTERISK, - OP_DUP_PLUS, - OP_DUP_QUESTION, - OP_BACK_REF, - ANCHOR, - OP_CONTEXT_NODE, - - /* Dummy marker. */ - END_OF_RE_TOKEN_T -} re_token_type_t; - -#ifdef RE_ENABLE_I18N -typedef struct -{ - /* Multibyte characters. */ - wchar_t *mbchars; - - /* Collating symbols. */ -# ifdef _LIBC - int32_t *coll_syms; -# endif - - /* Equivalence classes. */ -# ifdef _LIBC - int32_t *equiv_classes; -# endif - - /* Range expressions. */ -# ifdef _LIBC - uint32_t *range_starts; - uint32_t *range_ends; -# else /* not _LIBC */ - wchar_t *range_starts; - wchar_t *range_ends; -# endif /* not _LIBC */ - - /* Character classes. */ - wctype_t *char_classes; - - /* If this character set is the non-matching list. */ - unsigned int non_match : 1; - - /* # of multibyte characters. */ - int nmbchars; - - /* # of collating symbols. */ - int ncoll_syms; - - /* # of equivalence classes. */ - int nequiv_classes; - - /* # of range expressions. */ - int nranges; - - /* # of character classes. */ - int nchar_classes; -} re_charset_t; -#endif /* RE_ENABLE_I18N */ - -typedef struct -{ - union - { - unsigned char c; /* for CHARACTER */ - re_bitset_ptr_t sbcset; /* for SIMPLE_BRACKET */ -#ifdef RE_ENABLE_I18N - re_charset_t *mbcset; /* for COMPLEX_BRACKET */ -#endif /* RE_ENABLE_I18N */ - int idx; /* for BACK_REF */ - re_context_type ctx_type; /* for ANCHOR */ - struct - { - int entity; /* for OP_CONTEXT_NODE, index of the entity */ - re_node_set *bkref_eclosure; - } *ctx_info; - } opr; -#if __GNUC__ >= 2 - re_token_type_t type : 8; -#else - re_token_type_t type; -#endif - unsigned int constraint : 10; /* context constraint */ - unsigned int duplicated : 1; -#ifdef RE_ENABLE_I18N - unsigned int mb_partial : 1; -#endif -} re_token_t; - -#define IS_EPSILON_NODE(type) \ - ((type) == OP_ALT || (type) == OP_DUP_ASTERISK || (type) == OP_DUP_PLUS \ - || (type) == OP_DUP_QUESTION || (type) == ANCHOR \ - || (type) == OP_OPEN_SUBEXP || (type) == OP_CLOSE_SUBEXP) - -#define ACCEPT_MB_NODE(type) \ - ((type) == COMPLEX_BRACKET || (type) == OP_PERIOD) - -struct re_string_t -{ - /* Indicate the raw buffer which is the original string passed as an - argument of regexec(), re_search(), etc.. */ - const unsigned char *raw_mbs; - /* Store the multibyte string. In case of "case insensitive mode" like - REG_ICASE, upper cases of the string are stored, otherwise MBS points - the same address that RAW_MBS points. */ - unsigned char *mbs; - /* Store the case sensitive multibyte string. In case of - "case insensitive mode", the original string are stored, - otherwise MBS_CASE points the same address that MBS points. */ - unsigned char *mbs_case; -#ifdef RE_ENABLE_I18N - /* Store the wide character string which is corresponding to MBS. */ - wint_t *wcs; - mbstate_t cur_state; -#endif - /* Index in RAW_MBS. Each character mbs[i] corresponds to - raw_mbs[raw_mbs_idx + i]. */ - int raw_mbs_idx; - /* The length of the valid characters in the buffers. */ - int valid_len; - /* The length of the buffers MBS, MBS_CASE, and WCS. */ - int bufs_len; - /* The index in MBS, which is updated by re_string_fetch_byte. */ - int cur_idx; - /* This is length_of_RAW_MBS - RAW_MBS_IDX. */ - int len; - /* End of the buffer may be shorter than its length in the cases such - as re_match_2, re_search_2. Then, we use STOP for end of the buffer - instead of LEN. */ - int stop; - - /* The context of mbs[0]. We store the context independently, since - the context of mbs[0] may be different from raw_mbs[0], which is - the beginning of the input string. */ - unsigned int tip_context; - /* The translation passed as a part of an argument of re_compile_pattern. */ - RE_TRANSLATE_TYPE trans; - /* 1 if REG_ICASE. */ - unsigned int icase : 1; -}; -typedef struct re_string_t re_string_t; -/* In case of REG_ICASE, we allocate the buffer dynamically for mbs. */ -#define MBS_ALLOCATED(pstr) (pstr->icase) -/* In case that we need translation, we allocate the buffer dynamically - for mbs_case. Note that mbs == mbs_case if not REG_ICASE. */ -#define MBS_CASE_ALLOCATED(pstr) (pstr->trans != NULL) - - -static reg_errcode_t re_string_allocate (re_string_t *pstr, const char *str, - int len, int init_len, - RE_TRANSLATE_TYPE trans, int icase); -static reg_errcode_t re_string_construct (re_string_t *pstr, const char *str, - int len, RE_TRANSLATE_TYPE trans, - int icase); -static reg_errcode_t re_string_reconstruct (re_string_t *pstr, int idx, - int eflags, int newline); -static reg_errcode_t re_string_realloc_buffers (re_string_t *pstr, - int new_buf_len); -#ifdef RE_ENABLE_I18N -static void build_wcs_buffer (re_string_t *pstr); -static void build_wcs_upper_buffer (re_string_t *pstr); -#endif /* RE_ENABLE_I18N */ -static void build_upper_buffer (re_string_t *pstr); -static void re_string_translate_buffer (re_string_t *pstr); -static void re_string_destruct (re_string_t *pstr); -#ifdef RE_ENABLE_I18N -static int re_string_elem_size_at (const re_string_t *pstr, int idx); -static inline int re_string_char_size_at (const re_string_t *pstr, int idx); -static inline wint_t re_string_wchar_at (const re_string_t *pstr, int idx); -#endif /* RE_ENABLE_I18N */ -static unsigned int re_string_context_at (const re_string_t *input, int idx, - int eflags, int newline_anchor); -#define re_string_peek_byte(pstr, offset) \ - ((pstr)->mbs[(pstr)->cur_idx + offset]) -#define re_string_peek_byte_case(pstr, offset) \ - ((pstr)->mbs_case[(pstr)->cur_idx + offset]) -#define re_string_fetch_byte(pstr) \ - ((pstr)->mbs[(pstr)->cur_idx++]) -#define re_string_fetch_byte_case(pstr) \ - ((pstr)->mbs_case[(pstr)->cur_idx++]) -#define re_string_first_byte(pstr, idx) \ - ((idx) == (pstr)->len || (pstr)->wcs[idx] != WEOF) -#define re_string_is_single_byte_char(pstr, idx) \ - ((pstr)->wcs[idx] != WEOF && ((pstr)->len == (idx) \ - || (pstr)->wcs[(idx) + 1] != WEOF)) -#define re_string_eoi(pstr) ((pstr)->stop <= (pstr)->cur_idx) -#define re_string_cur_idx(pstr) ((pstr)->cur_idx) -#define re_string_get_buffer(pstr) ((pstr)->mbs) -#define re_string_length(pstr) ((pstr)->len) -#define re_string_byte_at(pstr,idx) ((pstr)->mbs[idx]) -#define re_string_skip_bytes(pstr,idx) ((pstr)->cur_idx += (idx)) -#define re_string_set_index(pstr,idx) ((pstr)->cur_idx = (idx)) - -#define re_malloc(t,n) ((t *) malloc ((n) * sizeof (t))) -#define re_realloc(p,t,n) ((t *) realloc (p, (n) * sizeof (t))) -#define re_free(p) free (p) - -struct bin_tree_t -{ - struct bin_tree_t *parent; - struct bin_tree_t *left; - struct bin_tree_t *right; - - /* `node_idx' is the index in dfa->nodes, if `type' == 0. - Otherwise `type' indicate the type of this node. */ - re_token_type_t type; - int node_idx; - - int first; - int next; - re_node_set eclosure; -}; -typedef struct bin_tree_t bin_tree_t; - - -#define CONTEXT_WORD 1 -#define CONTEXT_NEWLINE (CONTEXT_WORD << 1) -#define CONTEXT_BEGBUF (CONTEXT_NEWLINE << 1) -#define CONTEXT_ENDBUF (CONTEXT_BEGBUF << 1) - -#define IS_WORD_CONTEXT(c) ((c) & CONTEXT_WORD) -#define IS_NEWLINE_CONTEXT(c) ((c) & CONTEXT_NEWLINE) -#define IS_BEGBUF_CONTEXT(c) ((c) & CONTEXT_BEGBUF) -#define IS_ENDBUF_CONTEXT(c) ((c) & CONTEXT_ENDBUF) -#define IS_ORDINARY_CONTEXT(c) ((c) == 0) - -#define IS_WORD_CHAR(ch) (isalnum (ch) || (ch) == '_') -#define IS_NEWLINE(ch) ((ch) == NEWLINE_CHAR) - -#define NOT_SATISFY_PREV_CONSTRAINT(constraint,context) \ - ((((constraint) & PREV_WORD_CONSTRAINT) && !IS_WORD_CONTEXT (context)) \ - || ((constraint & PREV_NOTWORD_CONSTRAINT) && IS_WORD_CONTEXT (context)) \ - || ((constraint & PREV_NEWLINE_CONSTRAINT) && !IS_NEWLINE_CONTEXT (context))\ - || ((constraint & PREV_BEGBUF_CONSTRAINT) && !IS_BEGBUF_CONTEXT (context))) - -#define NOT_SATISFY_NEXT_CONSTRAINT(constraint,context) \ - ((((constraint) & NEXT_WORD_CONSTRAINT) && !IS_WORD_CONTEXT (context)) \ - || (((constraint) & NEXT_NOTWORD_CONSTRAINT) && IS_WORD_CONTEXT (context)) \ - || (((constraint) & NEXT_NEWLINE_CONSTRAINT) && !IS_NEWLINE_CONTEXT (context)) \ - || (((constraint) & NEXT_ENDBUF_CONSTRAINT) && !IS_ENDBUF_CONTEXT (context))) - -struct re_dfastate_t -{ - unsigned int hash; - re_node_set nodes; - re_node_set *entrance_nodes; - struct re_dfastate_t **trtable; - struct re_dfastate_t **trtable_search; - /* If this state is a special state. - A state is a special state if the state is the halt state, or - a anchor. */ - unsigned int context : 2; - unsigned int halt : 1; - /* If this state can accept `multi byte'. - Note that we refer to multibyte characters, and multi character - collating elements as `multi byte'. */ - unsigned int accept_mb : 1; - /* If this state has backreference node(s). */ - unsigned int has_backref : 1; - unsigned int has_constraint : 1; -}; -typedef struct re_dfastate_t re_dfastate_t; - -typedef struct -{ - /* start <= node < end */ - int start; - int end; -} re_subexp_t; - -struct re_state_table_entry -{ - int num; - int alloc; - re_dfastate_t **array; -}; - -struct re_backref_cache_entry -{ - int node; - int str_idx; - int subexp_from; - int subexp_to; - int flag; -}; - -typedef struct -{ - /* EFLAGS of the argument of regexec. */ - int eflags; - /* Where the matching ends. */ - int match_last; - int last_node; - /* The string object corresponding to the input string. */ - re_string_t *input; - /* The state log used by the matcher. */ - re_dfastate_t **state_log; - int state_log_top; - /* Back reference cache. */ - int nbkref_ents; - int abkref_ents; - struct re_backref_cache_entry *bkref_ents; - int max_mb_elem_len; -} re_match_context_t; - -typedef struct -{ - int cur_bkref; - int cls_subexp_idx; - - re_dfastate_t **sifted_states; - re_dfastate_t **limited_states; - - re_node_set limits; - - int last_node; - int last_str_idx; - int check_subexp; -} re_sift_context_t; - -struct re_fail_stack_ent_t -{ - int idx; - int node; - regmatch_t *regs; - re_node_set eps_via_nodes; -}; - -struct re_fail_stack_t -{ - int num; - int alloc; - struct re_fail_stack_ent_t *stack; -}; - -struct re_dfa_t -{ - re_bitset_ptr_t word_char; - - /* number of subexpressions `re_nsub' is in regex_t. */ - int subexps_alloc; - re_subexp_t *subexps; - - re_token_t *nodes; - int nodes_alloc; - int nodes_len; - bin_tree_t *str_tree; - int *firsts; - int *nexts; - re_node_set *edests; - re_node_set *eclosures; - re_node_set *inveclosures; - struct re_state_table_entry *state_table; - unsigned int state_hash_mask; - re_dfastate_t *init_state; - re_dfastate_t *init_state_word; - re_dfastate_t *init_state_nl; - re_dfastate_t *init_state_begbuf; - int states_alloc; - int init_node; - int nbackref; /* The number of backreference in this dfa. */ - /* If this dfa has "multibyte node", which is a backreference or - a node which can accept multibyte character or multi character - collating element. */ -#ifdef DEBUG - char* re_str; -#endif - unsigned int has_plural_match : 1; - unsigned int has_mb_node : 1; -}; -typedef struct re_dfa_t re_dfa_t; - -static reg_errcode_t re_node_set_alloc (re_node_set *set, int size); -static reg_errcode_t re_node_set_init_1 (re_node_set *set, int elem); -static reg_errcode_t re_node_set_init_2 (re_node_set *set, int elem1, - int elem2); -#define re_node_set_init_empty(set) memset (set, '\0', sizeof (re_node_set)) -static reg_errcode_t re_node_set_init_copy (re_node_set *dest, - const re_node_set *src); -static reg_errcode_t re_node_set_add_intersect (re_node_set *dest, - const re_node_set *src1, - const re_node_set *src2); -static reg_errcode_t re_node_set_init_union (re_node_set *dest, - const re_node_set *src1, - const re_node_set *src2); -static reg_errcode_t re_node_set_merge (re_node_set *dest, - const re_node_set *src); -static int re_node_set_insert (re_node_set *set, int elem); -static int re_node_set_compare (const re_node_set *set1, - const re_node_set *set2); -static int re_node_set_contains (const re_node_set *set, int elem); -static void re_node_set_remove_at (re_node_set *set, int idx); -#define re_node_set_empty(p) ((p)->nelem = 0) -#define re_node_set_free(set) re_free ((set)->elems) -static int re_dfa_add_node (re_dfa_t *dfa, re_token_t token, int mode); -static re_dfastate_t *re_acquire_state (reg_errcode_t *err, re_dfa_t *dfa, - const re_node_set *nodes); -static re_dfastate_t *re_acquire_state_context (reg_errcode_t *err, - re_dfa_t *dfa, - const re_node_set *nodes, - unsigned int context); - - -typedef enum -{ - SB_CHAR, - MB_CHAR, - EQUIV_CLASS, - COLL_SYM, - CHAR_CLASS -} bracket_elem_type; - -typedef struct -{ - bracket_elem_type type; - union - { - unsigned char ch; - unsigned char *name; - wchar_t wch; - } opr; -} bracket_elem_t; - - -/* Inline functions for bitset operation. */ -static inline void -bitset_not (set) - bitset set; -{ - int bitset_i; - for (bitset_i = 0; bitset_i < BITSET_UINTS; ++bitset_i) - set[bitset_i] = ~set[bitset_i]; -} - -static inline void -bitset_merge (dest, src) - bitset dest; - const bitset src; -{ - int bitset_i; - for (bitset_i = 0; bitset_i < BITSET_UINTS; ++bitset_i) - dest[bitset_i] |= src[bitset_i]; -} - -#if 0 /* gnupg */ -static inline void -bitset_not_merge (dest, src) - bitset dest; - const bitset src; -{ - int i; - for (i = 0; i < BITSET_UINTS; ++i) - dest[i] |= ~src[i]; -} -#endif - -#ifdef RE_ENABLE_I18N -/* Inline functions for re_string. */ -static inline int -re_string_char_size_at (pstr, idx) - const re_string_t *pstr; - int idx; -{ - int byte_idx; - if (MB_CUR_MAX == 1) - return 1; - for (byte_idx = 1; idx + byte_idx < pstr->len; ++byte_idx) - if (pstr->wcs[idx + byte_idx] != WEOF) - break; - return byte_idx; -} - -static inline wint_t -re_string_wchar_at (pstr, idx) - const re_string_t *pstr; - int idx; -{ - if (MB_CUR_MAX == 1) - return (wint_t) pstr->mbs[idx]; - return (wint_t) pstr->wcs[idx]; -} - -static int -re_string_elem_size_at (pstr, idx) - const re_string_t *pstr; - int idx; -{ -#ifdef _LIBC - const unsigned char *p, *extra; - const int32_t *table, *indirect; - int32_t tmp; -# include <locale/weight.h> - uint_fast32_t nrules = _NL_CURRENT_WORD (LC_COLLATE, _NL_COLLATE_NRULES); - - if (nrules != 0) - { - table = (const int32_t *) _NL_CURRENT (LC_COLLATE, _NL_COLLATE_TABLEMB); - extra = (const unsigned char *) - _NL_CURRENT (LC_COLLATE, _NL_COLLATE_EXTRAMB); - indirect = (const int32_t *) _NL_CURRENT (LC_COLLATE, - _NL_COLLATE_INDIRECTMB); - p = pstr->mbs + idx; - tmp = findidx (&p); - return p - pstr->mbs - idx; - } - else -#endif /* _LIBC */ - return 1; -} -#endif /* RE_ENABLE_I18N */ - -#endif /* _REGEX_INTERNAL_H */ diff --git a/util/regexec.c b/util/regexec.c deleted file mode 100644 index 40d305899..000000000 --- a/util/regexec.c +++ /dev/null @@ -1,3225 +0,0 @@ -/* Extended regular expression matching and search library. - Copyright (C) 2002 Free Software Foundation, Inc. - This file is part of the GNU C Library. - Contributed by Isamu Hasegawa <[email protected]>. - - The GNU C Library 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. - - The GNU C Library 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 the GNU C Library; if not, write to the Free - Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA - 02110-1301 USA. */ - -#include <assert.h> -#include <ctype.h> -#include <stdio.h> -#include <stdlib.h> -#include <string.h> - -#if defined HAVE_WCHAR_H || defined _LIBC -# include <wchar.h> -#endif /* HAVE_WCHAR_H || _LIBC */ -#if defined HAVE_WCTYPE_H || defined _LIBC -# include <wctype.h> -#endif /* HAVE_WCTYPE_H || _LIBC */ - -#ifdef _LIBC -# ifndef _RE_DEFINE_LOCALE_FUNCTIONS -# define _RE_DEFINE_LOCALE_FUNCTIONS 1 -# include <locale/localeinfo.h> -# include <locale/elem-hash.h> -# include <locale/coll-lookup.h> -# endif -#endif - -#include "_regex.h" /* gnupg */ -#include "regex_internal.h" - -static reg_errcode_t match_ctx_init (re_match_context_t *cache, int eflags, - re_string_t *input, int n); -static void match_ctx_free (re_match_context_t *cache); -static reg_errcode_t match_ctx_add_entry (re_match_context_t *cache, int node, - int str_idx, int from, int to); -static void match_ctx_clear_flag (re_match_context_t *mctx); -static void sift_ctx_init (re_sift_context_t *sctx, re_dfastate_t **sifted_sts, - re_dfastate_t **limited_sts, int last_node, - int last_str_idx, int check_subexp); -static reg_errcode_t re_search_internal (const regex_t *preg, - const char *string, int length, - int start, int range, int stop, - size_t nmatch, regmatch_t pmatch[], - int eflags); -static int re_search_2_stub (struct re_pattern_buffer *bufp, - const char *string1, int length1, - const char *string2, int length2, - int start, int range, struct re_registers *regs, - int stop, int ret_len); -static int re_search_stub (struct re_pattern_buffer *bufp, - const char *string, int length, int start, - int range, int stop, struct re_registers *regs, - int ret_len); -static unsigned re_copy_regs (struct re_registers *regs, regmatch_t *pmatch, - int nregs, int regs_allocated); -static inline re_dfastate_t *acquire_init_state_context (reg_errcode_t *err, - const regex_t *preg, - const re_match_context_t *mctx, - int idx); -static int check_matching (const regex_t *preg, re_match_context_t *mctx, - int fl_search, int fl_longest_match); -static int check_halt_node_context (const re_dfa_t *dfa, int node, - unsigned int context); -static int check_halt_state_context (const regex_t *preg, - const re_dfastate_t *state, - const re_match_context_t *mctx, int idx); -static void update_regs (re_dfa_t *dfa, regmatch_t *pmatch, int cur_node, - int cur_idx, int nmatch); -static int proceed_next_node (const regex_t *preg, int nregs, regmatch_t *regs, - const re_match_context_t *mctx, - int *pidx, int node, re_node_set *eps_via_nodes, - struct re_fail_stack_t *fs); -static reg_errcode_t push_fail_stack (struct re_fail_stack_t *fs, - int str_idx, int *dests, int nregs, - regmatch_t *regs, - re_node_set *eps_via_nodes); -static int pop_fail_stack (struct re_fail_stack_t *fs, int *pidx, int nregs, - regmatch_t *regs, re_node_set *eps_via_nodes); -static reg_errcode_t set_regs (const regex_t *preg, - const re_match_context_t *mctx, - size_t nmatch, regmatch_t *pmatch, - int fl_backtrack); -#ifdef RE_ENABLE_I18N -static int sift_states_iter_mb (const regex_t *preg, - const re_match_context_t *mctx, - re_sift_context_t *sctx, - int node_idx, int str_idx, int max_str_idx); -#endif /* RE_ENABLE_I18N */ -static reg_errcode_t sift_states_backward (const regex_t *preg, - re_match_context_t *mctx, - re_sift_context_t *sctx); -static reg_errcode_t update_cur_sifted_state (const regex_t *preg, - re_match_context_t *mctx, - re_sift_context_t *sctx, - int str_idx, - re_node_set *dest_nodes); -static reg_errcode_t add_epsilon_src_nodes (re_dfa_t *dfa, - re_node_set *dest_nodes, - const re_node_set *candidates); -static reg_errcode_t sub_epsilon_src_nodes (re_dfa_t *dfa, int node, - re_node_set *dest_nodes, - const re_node_set *and_nodes); -static int check_dst_limits (re_dfa_t *dfa, re_node_set *limits, - re_match_context_t *mctx, int dst_node, - int dst_idx, int src_node, int src_idx); -static int check_dst_limits_calc_pos (re_dfa_t *dfa, re_match_context_t *mctx, - int limit, re_node_set *eclosures, - int subexp_idx, int node, int str_idx); -static reg_errcode_t check_subexp_limits (re_dfa_t *dfa, - re_node_set *dest_nodes, - const re_node_set *candidates, - re_node_set *limits, - struct re_backref_cache_entry *bkref_ents, - int str_idx); -static reg_errcode_t search_subexp (const regex_t *preg, - re_match_context_t *mctx, - re_sift_context_t *sctx, int str_idx, - re_node_set *dest_nodes); -static reg_errcode_t sift_states_bkref (const regex_t *preg, - re_match_context_t *mctx, - re_sift_context_t *sctx, - int str_idx, re_node_set *dest_nodes); -static reg_errcode_t clean_state_log_if_need (re_match_context_t *mctx, - int next_state_log_idx); -static reg_errcode_t merge_state_array (re_dfa_t *dfa, re_dfastate_t **dst, - re_dfastate_t **src, int num); -static re_dfastate_t *transit_state (reg_errcode_t *err, const regex_t *preg, - re_match_context_t *mctx, - re_dfastate_t *state, int fl_search); -static re_dfastate_t *transit_state_sb (reg_errcode_t *err, const regex_t *preg, - re_dfastate_t *pstate, - int fl_search, - re_match_context_t *mctx); -#ifdef RE_ENABLE_I18N -static reg_errcode_t transit_state_mb (const regex_t *preg, - re_dfastate_t *pstate, - re_match_context_t *mctx); -#endif /* RE_ENABLE_I18N */ -static reg_errcode_t transit_state_bkref (const regex_t *preg, - re_dfastate_t *pstate, - re_match_context_t *mctx); -static reg_errcode_t transit_state_bkref_loop (const regex_t *preg, - re_node_set *nodes, - re_dfastate_t **work_state_log, - re_match_context_t *mctx); -static re_dfastate_t **build_trtable (const regex_t *dfa, - const re_dfastate_t *state, - int fl_search); -#ifdef RE_ENABLE_I18N -static int check_node_accept_bytes (const regex_t *preg, int node_idx, - const re_string_t *input, int idx); -# ifdef _LIBC -static unsigned int find_collation_sequence_value (const unsigned char *mbs, - size_t name_len); -# endif /* _LIBC */ -#endif /* RE_ENABLE_I18N */ -static int group_nodes_into_DFAstates (const regex_t *dfa, - const re_dfastate_t *state, - re_node_set *states_node, - bitset *states_ch); -static int check_node_accept (const regex_t *preg, const re_token_t *node, - const re_match_context_t *mctx, int idx); -static reg_errcode_t extend_buffers (re_match_context_t *mctx); - -/* Entry point for POSIX code. */ - -/* regexec searches for a given pattern, specified by PREG, in the - string STRING. - - If NMATCH is zero or REG_NOSUB was set in the cflags argument to - `regcomp', we ignore PMATCH. Otherwise, we assume PMATCH has at - least NMATCH elements, and we set them to the offsets of the - corresponding matched substrings. - - EFLAGS specifies `execution flags' which affect matching: if - REG_NOTBOL is set, then ^ does not match at the beginning of the - string; if REG_NOTEOL is set, then $ does not match at the end. - - We return 0 if we find a match and REG_NOMATCH if not. */ - -int -regexec (preg, string, nmatch, pmatch, eflags) - const regex_t *__restrict preg; - const char *__restrict string; - size_t nmatch; - regmatch_t pmatch[]; - int eflags; -{ - reg_errcode_t err; - int length = strlen (string); - if (preg->no_sub) - err = re_search_internal (preg, string, length, 0, length, length, 0, - NULL, eflags); - else - err = re_search_internal (preg, string, length, 0, length, length, nmatch, - pmatch, eflags); - return err != REG_NOERROR; -} -#ifdef _LIBC -weak_alias (__regexec, regexec) -#endif - -/* Entry points for GNU code. */ - -/* re_match, re_search, re_match_2, re_search_2 - - The former two functions operate on STRING with length LENGTH, - while the later two operate on concatenation of STRING1 and STRING2 - with lengths LENGTH1 and LENGTH2, respectively. - - re_match() matches the compiled pattern in BUFP against the string, - starting at index START. - - re_search() first tries matching at index START, then it tries to match - starting from index START + 1, and so on. The last start position tried - is START + RANGE. (Thus RANGE = 0 forces re_search to operate the same - way as re_match().) - - The parameter STOP of re_{match,search}_2 specifies that no match exceeding - the first STOP characters of the concatenation of the strings should be - concerned. - - If REGS is not NULL, and BUFP->no_sub is not set, the offsets of the match - and all groups is stroed in REGS. (For the "_2" variants, the offsets are - computed relative to the concatenation, not relative to the individual - strings.) - - On success, re_match* functions return the length of the match, re_search* - return the position of the start of the match. Return value -1 means no - match was found and -2 indicates an internal error. */ - -int -re_match (bufp, string, length, start, regs) - struct re_pattern_buffer *bufp; - const char *string; - int length, start; - struct re_registers *regs; -{ - return re_search_stub (bufp, string, length, start, 0, length, regs, 1); -} -#ifdef _LIBC -weak_alias (__re_match, re_match) -#endif - -int -re_search (bufp, string, length, start, range, regs) - struct re_pattern_buffer *bufp; - const char *string; - int length, start, range; - struct re_registers *regs; -{ - return re_search_stub (bufp, string, length, start, range, length, regs, 0); -} -#ifdef _LIBC -weak_alias (__re_search, re_search) -#endif - -int -re_match_2 (bufp, string1, length1, string2, length2, start, regs, stop) - struct re_pattern_buffer *bufp; - const char *string1, *string2; - int length1, length2, start, stop; - struct re_registers *regs; -{ - return re_search_2_stub (bufp, string1, length1, string2, length2, - start, 0, regs, stop, 1); -} -#ifdef _LIBC -weak_alias (__re_match_2, re_match_2) -#endif - -int -re_search_2 (bufp, string1, length1, string2, length2, start, range, regs, stop) - struct re_pattern_buffer *bufp; - const char *string1, *string2; - int length1, length2, start, range, stop; - struct re_registers *regs; -{ - return re_search_2_stub (bufp, string1, length1, string2, length2, - start, range, regs, stop, 0); -} -#ifdef _LIBC -weak_alias (__re_search_2, re_search_2) -#endif - -static int -re_search_2_stub (bufp, string1, length1, string2, length2, start, range, regs, - stop, ret_len) - struct re_pattern_buffer *bufp; - const char *string1, *string2; - int length1, length2, start, range, stop, ret_len; - struct re_registers *regs; -{ - const char *str; - int rval; - int len = length1 + length2; - int free_str = 0; - - if (BE (length1 < 0 || length2 < 0 || stop < 0, 0)) - return -2; - - /* Concatenate the strings. */ - if (length2 > 0) - if (length1 > 0) - { - char *s = re_malloc (char, len); - - if (BE (s == NULL, 0)) - return -2; - memcpy (s, string1, length1); - memcpy (s + length1, string2, length2); - str = s; - free_str = 1; - } - else - str = string2; - else - str = string1; - - rval = re_search_stub (bufp, str, len, start, range, stop, regs, - ret_len); - if (free_str) - re_free ((char *) str); - return rval; -} - -/* The parameters have the same meaning as those of re_search. - Additional parameters: - If RET_LEN is nonzero the length of the match is returned (re_match style); - otherwise the position of the match is returned. */ - -static int -re_search_stub (bufp, string, length, start, range, stop, regs, ret_len) - struct re_pattern_buffer *bufp; - const char *string; - int length, start, range, stop, ret_len; - struct re_registers *regs; -{ - reg_errcode_t result; - regmatch_t *pmatch; - int nregs, rval; - int eflags = 0; - - /* Check for out-of-range. */ - if (BE (start < 0 || start > length, 0)) - return -1; - if (BE (start + range > length, 0)) - range = length - start; - else if (BE (start + range < 0, 0)) - range = -start; - - eflags |= (bufp->not_bol) ? REG_NOTBOL : 0; - eflags |= (bufp->not_eol) ? REG_NOTEOL : 0; - - /* Compile fastmap if we haven't yet. */ - if (range > 0 && bufp->fastmap != NULL && !bufp->fastmap_accurate) - re_compile_fastmap (bufp); - - if (BE (bufp->no_sub, 0)) - regs = NULL; - - /* We need at least 1 register. */ - if (regs == NULL) - nregs = 1; - else if (BE (bufp->regs_allocated == REGS_FIXED && - regs->num_regs < bufp->re_nsub + 1, 0)) - { - nregs = regs->num_regs; - if (BE (nregs < 1, 0)) - { - /* Nothing can be copied to regs. */ - regs = NULL; - nregs = 1; - } - } - else - nregs = bufp->re_nsub + 1; - pmatch = re_malloc (regmatch_t, nregs); - if (BE (pmatch == NULL, 0)) - return -2; - - result = re_search_internal (bufp, string, length, start, range, stop, - nregs, pmatch, eflags); - - rval = 0; - - /* I hope we needn't fill ther regs with -1's when no match was found. */ - if (result != REG_NOERROR) - rval = -1; - else if (regs != NULL) - { - /* If caller wants register contents data back, copy them. */ - bufp->regs_allocated = re_copy_regs (regs, pmatch, nregs, - bufp->regs_allocated); - if (BE (bufp->regs_allocated == REGS_UNALLOCATED, 0)) - rval = -2; - } - - if (BE (rval == 0, 1)) - { - if (ret_len) - { - assert (pmatch[0].rm_so == start); - rval = pmatch[0].rm_eo - start; - } - else - rval = pmatch[0].rm_so; - } - re_free (pmatch); - return rval; -} - -static unsigned -re_copy_regs (regs, pmatch, nregs, regs_allocated) - struct re_registers *regs; - regmatch_t *pmatch; - int nregs, regs_allocated; -{ - int rval = REGS_REALLOCATE; - int i; - int need_regs = nregs + 1; - /* We need one extra element beyond `num_regs' for the `-1' marker GNU code - uses. */ - - /* Have the register data arrays been allocated? */ - if (regs_allocated == REGS_UNALLOCATED) - { /* No. So allocate them with malloc. */ - regs->start = re_malloc (regoff_t, need_regs); - if (BE (regs->start == NULL, 0)) - return REGS_UNALLOCATED; - regs->end = re_malloc (regoff_t, need_regs); - if (BE (regs->end == NULL, 0)) - { - re_free (regs->start); - return REGS_UNALLOCATED; - } - regs->num_regs = need_regs; - } - else if (regs_allocated == REGS_REALLOCATE) - { /* Yes. If we need more elements than were already - allocated, reallocate them. If we need fewer, just - leave it alone. */ - if (need_regs > regs->num_regs) - { - regs->start = re_realloc (regs->start, regoff_t, need_regs); - if (BE (regs->start == NULL, 0)) - { - if (regs->end != NULL) - re_free (regs->end); - return REGS_UNALLOCATED; - } - regs->end = re_realloc (regs->end, regoff_t, need_regs); - if (BE (regs->end == NULL, 0)) - { - re_free (regs->start); - return REGS_UNALLOCATED; - } - regs->num_regs = need_regs; - } - } - else - { - assert (regs_allocated == REGS_FIXED); - /* This function may not be called with REGS_FIXED and nregs too big. */ - assert (regs->num_regs >= nregs); - rval = REGS_FIXED; - } - - /* Copy the regs. */ - for (i = 0; i < nregs; ++i) - { - regs->start[i] = pmatch[i].rm_so; - regs->end[i] = pmatch[i].rm_eo; - } - for ( ; i < regs->num_regs; ++i) - regs->start[i] = regs->end[i] = -1; - - return rval; -} - -/* Set REGS to hold NUM_REGS registers, storing them in STARTS and - ENDS. Subsequent matches using PATTERN_BUFFER and REGS will use - this memory for recording register information. STARTS and ENDS - must be allocated using the malloc library routine, and must each - be at least NUM_REGS * sizeof (regoff_t) bytes long. - - If NUM_REGS == 0, then subsequent matches should allocate their own - register data. - - Unless this function is called, the first search or match using - PATTERN_BUFFER will allocate its own register data, without - freeing the old data. */ - -void -re_set_registers (bufp, regs, num_regs, starts, ends) - struct re_pattern_buffer *bufp; - struct re_registers *regs; - unsigned num_regs; - regoff_t *starts, *ends; -{ - if (num_regs) - { - bufp->regs_allocated = REGS_REALLOCATE; - regs->num_regs = num_regs; - regs->start = starts; - regs->end = ends; - } - else - { - bufp->regs_allocated = REGS_UNALLOCATED; - regs->num_regs = 0; - regs->start = regs->end = (regoff_t *) 0; - } -} -#ifdef _LIBC -weak_alias (__re_set_registers, re_set_registers) -#endif - -/* Entry points compatible with 4.2 BSD regex library. We don't define - them unless specifically requested. */ - -#if defined _REGEX_RE_COMP || defined _LIBC -int -# ifdef _LIBC -weak_function -# endif -re_exec (s) - const char *s; -{ - return 0 == regexec (&re_comp_buf, s, 0, NULL, 0); -} -#endif /* _REGEX_RE_COMP */ - -static re_node_set empty_set; - -/* Internal entry point. */ - -/* Searches for a compiled pattern PREG in the string STRING, whose - length is LENGTH. NMATCH, PMATCH, and EFLAGS have the same - mingings with regexec. START, and RANGE have the same meanings - with re_search. - Return REG_NOERROR if we find a match, and REG_NOMATCH if not, - otherwise return the error code. - Note: We assume front end functions already check ranges. - (START + RANGE >= 0 && START + RANGE <= LENGTH) */ - -static reg_errcode_t -re_search_internal (preg, string, length, start, range, stop, nmatch, pmatch, - eflags) - const regex_t *preg; - const char *string; - int length, start, range, stop, eflags; - size_t nmatch; - regmatch_t pmatch[]; -{ - reg_errcode_t err; - re_dfa_t *dfa = (re_dfa_t *)preg->buffer; - re_string_t input; - int left_lim, right_lim, incr; - int fl_longest_match, match_first, match_last = -1; - re_match_context_t mctx; - char *fastmap = ((preg->fastmap != NULL && preg->fastmap_accurate) - ? preg->fastmap : NULL); - - /* Check if the DFA haven't been compiled. */ - if (BE (preg->used == 0 || dfa->init_state == NULL - || dfa->init_state_word == NULL || dfa->init_state_nl == NULL - || dfa->init_state_begbuf == NULL, 0)) - return REG_NOMATCH; - - re_node_set_init_empty (&empty_set); - - /* We must check the longest matching, if nmatch > 0. */ - fl_longest_match = (nmatch != 0); - - err = re_string_allocate (&input, string, length, dfa->nodes_len + 1, - preg->translate, preg->syntax & RE_ICASE); - if (BE (err != REG_NOERROR, 0)) - return err; - input.stop = stop; - - err = match_ctx_init (&mctx, eflags, &input, dfa->nbackref * 2); - if (BE (err != REG_NOERROR, 0)) - return err; - - /* We will log all the DFA states through which the dfa pass, - if nmatch > 1, or this dfa has "multibyte node", which is a - back-reference or a node which can accept multibyte character or - multi character collating element. */ - if (nmatch > 1 || dfa->has_mb_node) - { - mctx.state_log = re_malloc (re_dfastate_t *, dfa->nodes_len + 1); - if (BE (mctx.state_log == NULL, 0)) - return REG_ESPACE; - } - else - mctx.state_log = NULL; - -#ifdef DEBUG - /* We assume front-end functions already check them. */ - assert (start + range >= 0 && start + range <= length); -#endif - - match_first = start; - input.tip_context = ((eflags & REG_NOTBOL) ? CONTEXT_BEGBUF - : CONTEXT_NEWLINE | CONTEXT_BEGBUF); - - /* Check incrementally whether of not the input string match. */ - incr = (range < 0) ? -1 : 1; - left_lim = (range < 0) ? start + range : start; - right_lim = (range < 0) ? start : start + range; - - for (;;) - { - /* At first get the current byte from input string. */ - int ch; - if (MB_CUR_MAX > 1 && (preg->syntax & RE_ICASE || preg->translate)) - { - /* In this case, we can't determin easily the current byte, - since it might be a component byte of a multibyte character. - Then we use the constructed buffer instead. */ - /* If MATCH_FIRST is out of the valid range, reconstruct the - buffers. */ - if (input.raw_mbs_idx + input.valid_len <= match_first) - re_string_reconstruct (&input, match_first, eflags, - preg->newline_anchor); - /* If MATCH_FIRST is out of the buffer, leave it as '\0'. - Note that MATCH_FIRST must not be smaller than 0. */ - ch = ((match_first >= length) ? 0 - : re_string_byte_at (&input, match_first - input.raw_mbs_idx)); - } - else - { - /* We apply translate/conversion manually, since it is trivial - in this case. */ - /* If MATCH_FIRST is out of the buffer, leave it as '\0'. - Note that MATCH_FIRST must not be smaller than 0. */ - ch = (match_first < length) ? (unsigned char)string[match_first] : 0; - /* Apply translation if we need. */ - ch = preg->translate ? preg->translate[ch] : ch; - /* In case of case insensitive mode, convert to upper case. */ - ch = ((preg->syntax & RE_ICASE) && islower (ch)) ? toupper (ch) : ch; - } - - /* Eliminate inappropriate one by fastmap. */ - if (preg->can_be_null || fastmap == NULL || fastmap[ch]) - { - /* Reconstruct the buffers so that the matcher can assume that - the matching starts from the begining of the buffer. */ - re_string_reconstruct (&input, match_first, eflags, - preg->newline_anchor); -#ifdef RE_ENABLE_I18N - /* Eliminate it when it is a component of a multibyte character - and isn't the head of a multibyte character. */ - if (MB_CUR_MAX == 1 || re_string_first_byte (&input, 0)) -#endif - { - /* It seems to be appropriate one, then use the matcher. */ - /* We assume that the matching starts from 0. */ - mctx.state_log_top = mctx.nbkref_ents = mctx.max_mb_elem_len = 0; - match_last = check_matching (preg, &mctx, 0, fl_longest_match); - if (match_last != -1) - { - if (BE (match_last == -2, 0)) - return REG_ESPACE; - else - break; /* We found a matching. */ - } - } - } - /* Update counter. */ - match_first += incr; - if (match_first < left_lim || right_lim < match_first) - break; - } - - /* Set pmatch[] if we need. */ - if (match_last != -1 && nmatch > 0) - { - int reg_idx; - - /* Initialize registers. */ - for (reg_idx = 0; reg_idx < nmatch; ++reg_idx) - pmatch[reg_idx].rm_so = pmatch[reg_idx].rm_eo = -1; - - /* Set the points where matching start/end. */ - pmatch[0].rm_so = 0; - mctx.match_last = pmatch[0].rm_eo = match_last; - - if (!preg->no_sub && nmatch > 1) - { - /* We need the ranges of all the subexpressions. */ - int halt_node; - re_dfastate_t **sifted_states; - re_dfastate_t **lim_states = NULL; - re_dfastate_t *pstate = mctx.state_log[match_last]; - re_sift_context_t sctx; -#ifdef DEBUG - assert (mctx.state_log != NULL); -#endif - halt_node = check_halt_state_context (preg, pstate, &mctx, - match_last); - if (dfa->has_plural_match) - { - match_ctx_clear_flag (&mctx); - sifted_states = re_malloc (re_dfastate_t *, match_last + 1); - if (BE (sifted_states == NULL, 0)) - return REG_ESPACE; - if (dfa->nbackref) - { - lim_states = calloc (sizeof (re_dfastate_t *), - match_last + 1); - if (BE (lim_states == NULL, 0)) - return REG_ESPACE; - } - sift_ctx_init (&sctx, sifted_states, lim_states, halt_node, - mctx.match_last, 0); - err = sift_states_backward (preg, &mctx, &sctx); - if (BE (err != REG_NOERROR, 0)) - return err; - if (lim_states != NULL) - { - err = merge_state_array (dfa, sifted_states, lim_states, - match_last + 1); - if (BE (err != REG_NOERROR, 0)) - return err; - re_free (lim_states); - } - re_node_set_free (&sctx.limits); - re_free (mctx.state_log); - mctx.state_log = sifted_states; - } - mctx.last_node = halt_node; - err = set_regs (preg, &mctx, nmatch, pmatch, - dfa->has_plural_match && dfa->nbackref > 0); - if (BE (err != REG_NOERROR, 0)) - return err; - } - - /* At last, add the offset to the each registers, since we slided - the buffers so that We can assume that the matching starts from 0. */ - for (reg_idx = 0; reg_idx < nmatch; ++reg_idx) - if (pmatch[reg_idx].rm_so != -1) - { - pmatch[reg_idx].rm_so += match_first; - pmatch[reg_idx].rm_eo += match_first; - } - } - - re_free (mctx.state_log); - if (dfa->nbackref) - match_ctx_free (&mctx); - re_string_destruct (&input); - - return (match_last == -1) ? REG_NOMATCH : REG_NOERROR; -} - -/* Acquire an initial state and return it. - We must select appropriate initial state depending on the context, - since initial states may have constraints like "\<", "^", etc.. */ - -static inline re_dfastate_t * -acquire_init_state_context (err, preg, mctx, idx) - reg_errcode_t *err; - const regex_t *preg; - const re_match_context_t *mctx; - int idx; -{ - re_dfa_t *dfa = (re_dfa_t *) preg->buffer; - - *err = REG_NOERROR; - if (dfa->init_state->has_constraint) - { - unsigned int context; - context = re_string_context_at (mctx->input, idx - 1, mctx->eflags, - preg->newline_anchor); - if (IS_WORD_CONTEXT (context)) - return dfa->init_state_word; - else if (IS_ORDINARY_CONTEXT (context)) - return dfa->init_state; - else if (IS_BEGBUF_CONTEXT (context) && IS_NEWLINE_CONTEXT (context)) - return dfa->init_state_begbuf; - else if (IS_NEWLINE_CONTEXT (context)) - return dfa->init_state_nl; - else if (IS_BEGBUF_CONTEXT (context)) - { - /* It is relatively rare case, then calculate on demand. */ - return re_acquire_state_context (err, dfa, - dfa->init_state->entrance_nodes, - context); - } - else - /* Must not happen? */ - return dfa->init_state; - } - else - return dfa->init_state; -} - -/* Check whether the regular expression match input string INPUT or not, - and return the index where the matching end, return -1 if not match, - or return -2 in case of an error. - FL_SEARCH means we must search where the matching starts, - FL_LONGEST_MATCH means we want the POSIX longest matching. - Note that the matcher assume that the maching starts from the current - index of the buffer. */ - -static int -check_matching (preg, mctx, fl_search, fl_longest_match) - const regex_t *preg; - re_match_context_t *mctx; - int fl_search, fl_longest_match; -{ - reg_errcode_t err; - int match = 0; - int match_last = -1; - int cur_str_idx = re_string_cur_idx (mctx->input); - re_dfastate_t *cur_state; - - cur_state = acquire_init_state_context (&err, preg, mctx, cur_str_idx); - /* An initial state must not be NULL(invalid state). */ - if (BE (cur_state == NULL, 0)) - return -2; - if (mctx->state_log != NULL) - mctx->state_log[cur_str_idx] = cur_state; - - if (cur_state->has_backref) - { - int i; - re_dfa_t *dfa = (re_dfa_t *) preg->buffer; - for (i = 0; i < cur_state->nodes.nelem; ++i) - { - re_token_type_t type; - int node = cur_state->nodes.elems[i]; - int entity = (dfa->nodes[node].type != OP_CONTEXT_NODE ? node - : dfa->nodes[node].opr.ctx_info->entity); - type = dfa->nodes[entity].type; - if (type == OP_BACK_REF) - { - int clexp_idx; - for (clexp_idx = 0; clexp_idx < cur_state->nodes.nelem; - ++clexp_idx) - { - re_token_t *clexp_node; - clexp_node = dfa->nodes + cur_state->nodes.elems[clexp_idx]; - if (clexp_node->type == OP_CLOSE_SUBEXP - && clexp_node->opr.idx + 1== dfa->nodes[entity].opr.idx) - { - err = match_ctx_add_entry (mctx, node, 0, 0, 0); - if (BE (err != REG_NOERROR, 0)) - return -2; - break; - } - } - } - } - } - - /* If the RE accepts NULL string. */ - if (cur_state->halt) - { - if (!cur_state->has_constraint - || check_halt_state_context (preg, cur_state, mctx, cur_str_idx)) - { - if (!fl_longest_match) - return cur_str_idx; - else - { - match_last = cur_str_idx; - match = 1; - } - } - } - - while (!re_string_eoi (mctx->input)) - { - cur_state = transit_state (&err, preg, mctx, cur_state, - fl_search && !match); - if (cur_state == NULL) /* Reached at the invalid state or an error. */ - { - cur_str_idx = re_string_cur_idx (mctx->input); - if (BE (err != REG_NOERROR, 0)) - return -2; - if (fl_search && !match) - { - /* Restart from initial state, since we are searching - the point from where matching start. */ -#ifdef RE_ENABLE_I18N - if (MB_CUR_MAX == 1 - || re_string_first_byte (mctx->input, cur_str_idx)) -#endif /* RE_ENABLE_I18N */ - cur_state = acquire_init_state_context (&err, preg, mctx, - cur_str_idx); - if (BE (cur_state == NULL && err != REG_NOERROR, 0)) - return -2; - if (mctx->state_log != NULL) - mctx->state_log[cur_str_idx] = cur_state; - } - else if (!fl_longest_match && match) - break; - else /* (fl_longest_match && match) || (!fl_search && !match) */ - { - if (mctx->state_log == NULL) - break; - else - { - int max = mctx->state_log_top; - for (; cur_str_idx <= max; ++cur_str_idx) - if (mctx->state_log[cur_str_idx] != NULL) - break; - if (cur_str_idx > max) - break; - } - } - } - - if (cur_state != NULL && cur_state->halt) - { - /* Reached at a halt state. - Check the halt state can satisfy the current context. */ - if (!cur_state->has_constraint - || check_halt_state_context (preg, cur_state, mctx, - re_string_cur_idx (mctx->input))) - { - /* We found an appropriate halt state. */ - match_last = re_string_cur_idx (mctx->input); - match = 1; - if (!fl_longest_match) - break; - } - } - } - return match_last; -} - -/* Check NODE match the current context. */ - -static int check_halt_node_context (dfa, node, context) - const re_dfa_t *dfa; - int node; - unsigned int context; -{ - int entity; - re_token_type_t type = dfa->nodes[node].type; - if (type == END_OF_RE) - return 1; - if (type != OP_CONTEXT_NODE) - return 0; - entity = dfa->nodes[node].opr.ctx_info->entity; - if (dfa->nodes[entity].type != END_OF_RE - || NOT_SATISFY_NEXT_CONSTRAINT (dfa->nodes[node].constraint, context)) - return 0; - return 1; -} - -/* Check the halt state STATE match the current context. - Return 0 if not match, if the node, STATE has, is a halt node and - match the context, return the node. */ - -static int -check_halt_state_context (preg, state, mctx, idx) - const regex_t *preg; - const re_dfastate_t *state; - const re_match_context_t *mctx; - int idx; -{ - re_dfa_t *dfa = (re_dfa_t *) preg->buffer; - int i; - unsigned int context; -#ifdef DEBUG - assert (state->halt); -#endif - context = re_string_context_at (mctx->input, idx, mctx->eflags, - preg->newline_anchor); - for (i = 0; i < state->nodes.nelem; ++i) - if (check_halt_node_context (dfa, state->nodes.elems[i], context)) - return state->nodes.elems[i]; - return 0; -} - -/* Compute the next node to which "NFA" transit from NODE("NFA" is a NFA - corresponding to the DFA). - Return the destination node, and update EPS_VIA_NODES, return -1 in case - of errors. */ - -static int -proceed_next_node (preg, nregs, regs, mctx, pidx, node, eps_via_nodes, fs) - const regex_t *preg; - regmatch_t *regs; - const re_match_context_t *mctx; - int nregs, *pidx, node; - re_node_set *eps_via_nodes; - struct re_fail_stack_t *fs; -{ - re_dfa_t *dfa = (re_dfa_t *)preg->buffer; - int i, err, dest_node, cur_entity; - dest_node = -1; - cur_entity = ((dfa->nodes[node].type == OP_CONTEXT_NODE) - ? dfa->nodes[node].opr.ctx_info->entity : node); - if (IS_EPSILON_NODE (dfa->nodes[node].type)) - { - int ndest, dest_nodes[2], dest_entities[2]; - err = re_node_set_insert (eps_via_nodes, node); - if (BE (err < 0, 0)) - return -1; - /* Pick up valid destinations. */ - for (ndest = 0, i = 0; i < mctx->state_log[*pidx]->nodes.nelem; ++i) - { - int candidate = mctx->state_log[*pidx]->nodes.elems[i]; - int entity; - entity = ((dfa->nodes[candidate].type == OP_CONTEXT_NODE) - ? dfa->nodes[candidate].opr.ctx_info->entity : candidate); - if (!re_node_set_contains (dfa->edests + node, entity)) - continue; - dest_nodes[0] = (ndest == 0) ? candidate : dest_nodes[0]; - dest_entities[0] = (ndest == 0) ? entity : dest_entities[0]; - dest_nodes[1] = (ndest == 1) ? candidate : dest_nodes[1]; - dest_entities[1] = (ndest == 1) ? entity : dest_entities[1]; - ++ndest; - } - if (ndest <= 1) - return ndest == 0 ? -1 : (ndest == 1 ? dest_nodes[0] : 0); - if (dest_entities[0] > dest_entities[1]) - { - int swap_work = dest_nodes[0]; - dest_nodes[0] = dest_nodes[1]; - dest_nodes[1] = swap_work; - } - /* In order to avoid infinite loop like "(a*)*". */ - if (re_node_set_contains (eps_via_nodes, dest_nodes[0])) - return dest_nodes[1]; - if (fs != NULL) - push_fail_stack (fs, *pidx, dest_nodes, nregs, regs, eps_via_nodes); - return dest_nodes[0]; - } - else - { - int naccepted = 0, entity = node; - re_token_type_t type = dfa->nodes[node].type; - if (type == OP_CONTEXT_NODE) - { - entity = dfa->nodes[node].opr.ctx_info->entity; - type = dfa->nodes[entity].type; - } - -#ifdef RE_ENABLE_I18N - if (ACCEPT_MB_NODE (type)) - naccepted = check_node_accept_bytes (preg, entity, mctx->input, *pidx); - else -#endif /* RE_ENABLE_I18N */ - if (type == OP_BACK_REF) - { - int subexp_idx = dfa->nodes[entity].opr.idx; - naccepted = regs[subexp_idx].rm_eo - regs[subexp_idx].rm_so; - if (fs != NULL) - { - if (regs[subexp_idx].rm_so == -1 || regs[subexp_idx].rm_eo == -1) - return -1; - else if (naccepted) - { - char *buf = re_string_get_buffer (mctx->input); - if (strncmp (buf + regs[subexp_idx].rm_so, buf + *pidx, - naccepted) != 0) - return -1; - } - } - - if (naccepted == 0) - { - err = re_node_set_insert (eps_via_nodes, node); - if (BE (err < 0, 0)) - return -2; - dest_node = dfa->nexts[node]; - if (re_node_set_contains (&mctx->state_log[*pidx]->nodes, - dest_node)) - return dest_node; - for (i = 0; i < mctx->state_log[*pidx]->nodes.nelem; ++i) - { - dest_node = mctx->state_log[*pidx]->nodes.elems[i]; - if ((dfa->nodes[dest_node].type == OP_CONTEXT_NODE - && (dfa->nexts[node] - == dfa->nodes[dest_node].opr.ctx_info->entity))) - return dest_node; - } - } - } - - if (naccepted != 0 - || check_node_accept (preg, dfa->nodes + node, mctx, *pidx)) - { - dest_node = dfa->nexts[node]; - *pidx = (naccepted == 0) ? *pidx + 1 : *pidx + naccepted; - if (fs && (*pidx > mctx->match_last || mctx->state_log[*pidx] == NULL - || !re_node_set_contains (&mctx->state_log[*pidx]->nodes, - dest_node))) - return -1; - re_node_set_empty (eps_via_nodes); - return dest_node; - } - } - return -1; -} - -static reg_errcode_t -push_fail_stack (fs, str_idx, dests, nregs, regs, eps_via_nodes) - struct re_fail_stack_t *fs; - int str_idx, *dests, nregs; - regmatch_t *regs; - re_node_set *eps_via_nodes; -{ - reg_errcode_t err; - int num = fs->num++; - if (fs->num == fs->alloc) - { - fs->alloc *= 2; - fs->stack = realloc (fs->stack, (sizeof (struct re_fail_stack_ent_t) - * fs->alloc)); - if (fs->stack == NULL) - return REG_ESPACE; - } - fs->stack[num].idx = str_idx; - fs->stack[num].node = dests[1]; - fs->stack[num].regs = re_malloc (regmatch_t, nregs); - memcpy (fs->stack[num].regs, regs, sizeof (regmatch_t) * nregs); - err = re_node_set_init_copy (&fs->stack[num].eps_via_nodes, eps_via_nodes); - return err; -} - -static int -pop_fail_stack (fs, pidx, nregs, regs, eps_via_nodes) - struct re_fail_stack_t *fs; - int *pidx, nregs; - regmatch_t *regs; - re_node_set *eps_via_nodes; -{ - int num = --fs->num; - assert (num >= 0); - *pidx = fs->stack[num].idx; - memcpy (regs, fs->stack[num].regs, sizeof (regmatch_t) * nregs); - re_node_set_free (eps_via_nodes); - *eps_via_nodes = fs->stack[num].eps_via_nodes; - return fs->stack[num].node; -} - -/* Set the positions where the subexpressions are starts/ends to registers - PMATCH. - Note: We assume that pmatch[0] is already set, and - pmatch[i].rm_so == pmatch[i].rm_eo == -1 (i > 1). */ - -static reg_errcode_t -set_regs (preg, mctx, nmatch, pmatch, fl_backtrack) - const regex_t *preg; - const re_match_context_t *mctx; - size_t nmatch; - regmatch_t *pmatch; - int fl_backtrack; -{ - re_dfa_t *dfa = (re_dfa_t *)preg->buffer; - int idx, cur_node, real_nmatch; - re_node_set eps_via_nodes; - struct re_fail_stack_t *fs; - struct re_fail_stack_t fs_body = {0, 2, NULL}; -#ifdef DEBUG - assert (nmatch > 1); - assert (mctx->state_log != NULL); -#endif - if (fl_backtrack) - { - fs = &fs_body; - fs->stack = re_malloc (struct re_fail_stack_ent_t, fs->alloc); - } - else - fs = NULL; - cur_node = dfa->init_node; - real_nmatch = (nmatch <= preg->re_nsub) ? nmatch : preg->re_nsub + 1; - re_node_set_init_empty (&eps_via_nodes); - for (idx = pmatch[0].rm_so; idx <= pmatch[0].rm_eo ;) - { - update_regs (dfa, pmatch, cur_node, idx, real_nmatch); - if (idx == pmatch[0].rm_eo && cur_node == mctx->last_node) - { - int reg_idx; - if (fs) - { - for (reg_idx = 0; reg_idx < nmatch; ++reg_idx) - if (pmatch[reg_idx].rm_so > -1 && pmatch[reg_idx].rm_eo == -1) - break; - if (reg_idx == nmatch) - return REG_NOERROR; - cur_node = pop_fail_stack (fs, &idx, nmatch, pmatch, - &eps_via_nodes); - } - else - return REG_NOERROR; - } - - /* Proceed to next node. */ - cur_node = proceed_next_node (preg, nmatch, pmatch, mctx, &idx, cur_node, - &eps_via_nodes, fs); - - if (BE (cur_node < 0, 0)) - { - if (cur_node == -2) - return REG_ESPACE; - if (fs) - cur_node = pop_fail_stack (fs, &idx, nmatch, pmatch, - &eps_via_nodes); - else - return REG_NOMATCH; - } - } - re_node_set_free (&eps_via_nodes); - return REG_NOERROR; -} - -static void -update_regs (dfa, pmatch, cur_node, cur_idx, nmatch) - re_dfa_t *dfa; - regmatch_t *pmatch; - int cur_node, cur_idx, nmatch; -{ - int type = dfa->nodes[cur_node].type; - int reg_num; - if (type != OP_OPEN_SUBEXP && type != OP_CLOSE_SUBEXP) - return; - reg_num = dfa->nodes[cur_node].opr.idx + 1; - if (reg_num >= nmatch) - return; - if (type == OP_OPEN_SUBEXP) - { - /* We are at the first node of this sub expression. */ - pmatch[reg_num].rm_so = cur_idx; - pmatch[reg_num].rm_eo = -1; - } - else if (type == OP_CLOSE_SUBEXP) - /* We are at the first node of this sub expression. */ - pmatch[reg_num].rm_eo = cur_idx; -} - -#define NUMBER_OF_STATE 1 - -/* This function checks the STATE_LOG from the SCTX->last_str_idx to 0 - and sift the nodes in each states according to the following rules. - Updated state_log will be wrote to STATE_LOG. - - Rules: We throw away the Node `a' in the STATE_LOG[STR_IDX] if... - 1. When STR_IDX == MATCH_LAST(the last index in the state_log): - If `a' isn't the LAST_NODE and `a' can't epsilon transit to - the LAST_NODE, we throw away the node `a'. - 2. When 0 <= STR_IDX < MATCH_LAST and `a' accepts - string `s' and transit to `b': - i. If 'b' isn't in the STATE_LOG[STR_IDX+strlen('s')], we throw - away the node `a'. - ii. If 'b' is in the STATE_LOG[STR_IDX+strlen('s')] but 'b' is - throwed away, we throw away the node `a'. - 3. When 0 <= STR_IDX < n and 'a' epsilon transit to 'b': - i. If 'b' isn't in the STATE_LOG[STR_IDX], we throw away the - node `a'. - ii. If 'b' is in the STATE_LOG[STR_IDX] but 'b' is throwed away, - we throw away the node `a'. */ - -#define STATE_NODE_CONTAINS(state,node) \ - ((state) != NULL && re_node_set_contains (&(state)->nodes, node)) - -static reg_errcode_t -sift_states_backward (preg, mctx, sctx) - const regex_t *preg; - re_match_context_t *mctx; - re_sift_context_t *sctx; -{ - reg_errcode_t err; - re_dfa_t *dfa = (re_dfa_t *)preg->buffer; - int null_cnt = 0; - int str_idx = sctx->last_str_idx; - re_node_set cur_dest; - re_node_set *cur_src; /* Points the state_log[str_idx]->nodes */ - -#ifdef DEBUG - assert (mctx->state_log != NULL && mctx->state_log[str_idx] != NULL); -#endif - cur_src = &mctx->state_log[str_idx]->nodes; - - /* Build sifted state_log[str_idx]. It has the nodes which can epsilon - transit to the last_node and the last_node itself. */ - err = re_node_set_init_1 (&cur_dest, sctx->last_node); - if (BE (err != REG_NOERROR, 0)) - return err; - err = update_cur_sifted_state (preg, mctx, sctx, str_idx, &cur_dest); - if (BE (err != REG_NOERROR, 0)) - return err; - - /* Then check each states in the state_log. */ - while (str_idx > 0) - { - int i, ret; - /* Update counters. */ - null_cnt = (sctx->sifted_states[str_idx] == NULL) ? null_cnt + 1 : 0; - if (null_cnt > mctx->max_mb_elem_len) - { - memset (sctx->sifted_states, '\0', - sizeof (re_dfastate_t *) * str_idx); - return REG_NOERROR; - } - re_node_set_empty (&cur_dest); - --str_idx; - cur_src = ((mctx->state_log[str_idx] == NULL) ? &empty_set - : &mctx->state_log[str_idx]->nodes); - - /* Then build the next sifted state. - We build the next sifted state on `cur_dest', and update - `sifted_states[str_idx]' with `cur_dest'. - Note: - `cur_dest' is the sifted state from `state_log[str_idx + 1]'. - `cur_src' points the node_set of the old `state_log[str_idx]'. */ - for (i = 0; i < cur_src->nelem; i++) - { - int prev_node = cur_src->elems[i]; - int entity = prev_node; - int naccepted = 0; - re_token_type_t type = dfa->nodes[prev_node].type; - - if (IS_EPSILON_NODE(type)) - continue; - if (type == OP_CONTEXT_NODE) - { - entity = dfa->nodes[prev_node].opr.ctx_info->entity; - type = dfa->nodes[entity].type; - } -#ifdef RE_ENABLE_I18N - /* If the node may accept `multi byte'. */ - if (ACCEPT_MB_NODE (type)) - naccepted = sift_states_iter_mb (preg, mctx, sctx, entity, str_idx, - sctx->last_str_idx); - -#endif /* RE_ENABLE_I18N */ - /* We don't check backreferences here. - See update_cur_sifted_state(). */ - - if (!naccepted - && check_node_accept (preg, dfa->nodes + prev_node, mctx, - str_idx) - && STATE_NODE_CONTAINS (sctx->sifted_states[str_idx + 1], - dfa->nexts[prev_node])) - naccepted = 1; - - if (naccepted == 0) - continue; - - if (sctx->limits.nelem) - { - int to_idx = str_idx + naccepted; - if (check_dst_limits (dfa, &sctx->limits, mctx, - dfa->nexts[prev_node], to_idx, - prev_node, str_idx)) - continue; - } - ret = re_node_set_insert (&cur_dest, prev_node); - if (BE (ret == -1, 0)) - return err; - } - - /* Add all the nodes which satisfy the following conditions: - - It can epsilon transit to a node in CUR_DEST. - - It is in CUR_SRC. - And update state_log. */ - err = update_cur_sifted_state (preg, mctx, sctx, str_idx, &cur_dest); - if (BE (err != REG_NOERROR, 0)) - return err; - } - - re_node_set_free (&cur_dest); - return REG_NOERROR; -} - -/* Helper functions. */ - -static inline reg_errcode_t -clean_state_log_if_need (mctx, next_state_log_idx) - re_match_context_t *mctx; - int next_state_log_idx; -{ - int top = mctx->state_log_top; - - if (next_state_log_idx >= mctx->input->bufs_len - || (next_state_log_idx >= mctx->input->valid_len - && mctx->input->valid_len < mctx->input->len)) - { - reg_errcode_t err; - err = extend_buffers (mctx); - if (BE (err != REG_NOERROR, 0)) - return err; - } - - if (top < next_state_log_idx) - { - memset (mctx->state_log + top + 1, '\0', - sizeof (re_dfastate_t *) * (next_state_log_idx - top)); - mctx->state_log_top = next_state_log_idx; - } - return REG_NOERROR; -} - -static reg_errcode_t merge_state_array (dfa, dst, src, num) - re_dfa_t *dfa; - re_dfastate_t **dst; - re_dfastate_t **src; - int num; -{ - int st_idx; - reg_errcode_t err; - for (st_idx = 0; st_idx < num; ++st_idx) - { - if (dst[st_idx] == NULL) - dst[st_idx] = src[st_idx]; - else if (src[st_idx] != NULL) - { - re_node_set merged_set; - err = re_node_set_init_union (&merged_set, &dst[st_idx]->nodes, - &src[st_idx]->nodes); - if (BE (err != REG_NOERROR, 0)) - return err; - dst[st_idx] = re_acquire_state (&err, dfa, &merged_set); - if (BE (err != REG_NOERROR, 0)) - return err; - re_node_set_free (&merged_set); - } - } - return REG_NOERROR; -} - -static reg_errcode_t -update_cur_sifted_state (preg, mctx, sctx, str_idx, dest_nodes) - const regex_t *preg; - re_match_context_t *mctx; - re_sift_context_t *sctx; - int str_idx; - re_node_set *dest_nodes; -{ - reg_errcode_t err; - re_dfa_t *dfa = (re_dfa_t *)preg->buffer; - const re_node_set *candidates; - candidates = ((mctx->state_log[str_idx] == NULL) ? &empty_set - : &mctx->state_log[str_idx]->nodes); - - /* At first, add the nodes which can epsilon transit to a node in - DEST_NODE. */ - err = add_epsilon_src_nodes (dfa, dest_nodes, candidates); - if (BE (err != REG_NOERROR, 0)) - return err; - - /* Then, check the limitations in the current sift_context. */ - if (sctx->limits.nelem) - { - err = check_subexp_limits (dfa, dest_nodes, candidates, &sctx->limits, - mctx->bkref_ents, str_idx); - if (BE (err != REG_NOERROR, 0)) - return err; - } - - /* Update state_log. */ - sctx->sifted_states[str_idx] = re_acquire_state (&err, dfa, dest_nodes); - if (BE (sctx->sifted_states[str_idx] == NULL && err != REG_NOERROR, 0)) - return err; - - /* If we are searching for the subexpression candidates. - Note that we were from transit_state_bkref_loop() in this case. */ - if (sctx->check_subexp) - { - err = search_subexp (preg, mctx, sctx, str_idx, dest_nodes); - if (BE (err != REG_NOERROR, 0)) - return err; - } - - if ((mctx->state_log[str_idx] != NULL - && mctx->state_log[str_idx]->has_backref)) - { - err = sift_states_bkref (preg, mctx, sctx, str_idx, dest_nodes); - if (BE (err != REG_NOERROR, 0)) - return err; - } - return REG_NOERROR; -} - -static reg_errcode_t -add_epsilon_src_nodes (dfa, dest_nodes, candidates) - re_dfa_t *dfa; - re_node_set *dest_nodes; - const re_node_set *candidates; -{ - reg_errcode_t err; - int src_idx; - re_node_set src_copy; - - err = re_node_set_init_copy (&src_copy, dest_nodes); - if (BE (err != REG_NOERROR, 0)) - return err; - for (src_idx = 0; src_idx < src_copy.nelem; ++src_idx) - { - err = re_node_set_add_intersect (dest_nodes, candidates, - dfa->inveclosures - + src_copy.elems[src_idx]); - if (BE (err != REG_NOERROR, 0)) - return err; - } - re_node_set_free (&src_copy); - return REG_NOERROR; -} - -static reg_errcode_t -sub_epsilon_src_nodes (dfa, node, dest_nodes, candidates) - re_dfa_t *dfa; - int node; - re_node_set *dest_nodes; - const re_node_set *candidates; -{ - int ecl_idx; - reg_errcode_t err; - re_node_set *inv_eclosure = dfa->inveclosures + node; - re_node_set except_nodes; - re_node_set_init_empty (&except_nodes); - for (ecl_idx = 0; ecl_idx < inv_eclosure->nelem; ++ecl_idx) - { - int cur_node = inv_eclosure->elems[ecl_idx]; - if (cur_node == node) - continue; - if (dfa->edests[cur_node].nelem) - { - int edst1 = dfa->edests[cur_node].elems[0]; - int edst2 = ((dfa->edests[cur_node].nelem > 1) - ? dfa->edests[cur_node].elems[1] : -1); - if ((!re_node_set_contains (inv_eclosure, edst1) - && re_node_set_contains (dest_nodes, edst1)) - || (edst2 > 0 - && !re_node_set_contains (inv_eclosure, edst2) - && re_node_set_contains (dest_nodes, edst2))) - { - err = re_node_set_add_intersect (&except_nodes, candidates, - dfa->inveclosures + cur_node); - if (BE (err != REG_NOERROR, 0)) - return err; - } - } - } - for (ecl_idx = 0; ecl_idx < inv_eclosure->nelem; ++ecl_idx) - { - int cur_node = inv_eclosure->elems[ecl_idx]; - if (!re_node_set_contains (&except_nodes, cur_node)) - { - int idx = re_node_set_contains (dest_nodes, cur_node) - 1; - re_node_set_remove_at (dest_nodes, idx); - } - } - re_node_set_free (&except_nodes); - return REG_NOERROR; -} - -static int -check_dst_limits (dfa, limits, mctx, dst_node, dst_idx, src_node, src_idx) - re_dfa_t *dfa; - re_node_set *limits; - re_match_context_t *mctx; - int dst_node, dst_idx, src_node, src_idx; -{ - int lim_idx, src_pos, dst_pos; - - for (lim_idx = 0; lim_idx < limits->nelem; ++lim_idx) - { - int bkref, subexp_idx/*, node_idx, cls_node*/; - struct re_backref_cache_entry *ent; - ent = mctx->bkref_ents + limits->elems[lim_idx]; - bkref = (dfa->nodes[ent->node].type == OP_CONTEXT_NODE - ? dfa->nodes[ent->node].opr.ctx_info->entity : ent->node); - subexp_idx = dfa->nodes[bkref].opr.idx - 1; - - dst_pos = check_dst_limits_calc_pos (dfa, mctx, limits->elems[lim_idx], - dfa->eclosures + dst_node, - subexp_idx, dst_node, dst_idx); - src_pos = check_dst_limits_calc_pos (dfa, mctx, limits->elems[lim_idx], - dfa->eclosures + src_node, - subexp_idx, src_node, src_idx); - - /* In case of: - <src> <dst> ( <subexp> ) - ( <subexp> ) <src> <dst> - ( <subexp1> <src> <subexp2> <dst> <subexp3> ) */ - if (src_pos == dst_pos) - continue; /* This is unrelated limitation. */ - else - return 1; - } - return 0; -} - -static int -check_dst_limits_calc_pos (dfa, mctx, limit, eclosures, subexp_idx, node, - str_idx) - re_dfa_t *dfa; - re_match_context_t *mctx; - re_node_set *eclosures; - int limit, subexp_idx, node, str_idx; -{ - struct re_backref_cache_entry *lim = mctx->bkref_ents + limit; - int pos = (str_idx < lim->subexp_from ? -1 - : (lim->subexp_to < str_idx ? 1 : 0)); - if (pos == 0 - && (str_idx == lim->subexp_from || str_idx == lim->subexp_to)) - { - int node_idx; - for (node_idx = 0; node_idx < eclosures->nelem; ++node_idx) - { - int node = eclosures->elems[node_idx]; - int entity = node; - re_token_type_t type= dfa->nodes[node].type; - if (type == OP_CONTEXT_NODE) - { - entity = dfa->nodes[node].opr.ctx_info->entity; - type = dfa->nodes[entity].type; - } - if (type == OP_BACK_REF) - { - int bi; - for (bi = 0; bi < mctx->nbkref_ents; ++bi) - { - struct re_backref_cache_entry *ent = mctx->bkref_ents + bi; - if (ent->node == node && ent->subexp_from == ent->subexp_to - && ent->str_idx == str_idx) - { - int cpos, dst; - dst = dfa->nexts[node]; - cpos = check_dst_limits_calc_pos (dfa, mctx, limit, - dfa->eclosures + dst, - subexp_idx, dst, - str_idx); - if ((str_idx == lim->subexp_from && cpos == -1) - || (str_idx == lim->subexp_to && cpos == 0)) - return cpos; - } - } - } - if (type == OP_OPEN_SUBEXP && subexp_idx == dfa->nodes[node].opr.idx - && str_idx == lim->subexp_from) - { - pos = -1; - break; - } - if (type == OP_CLOSE_SUBEXP && subexp_idx == dfa->nodes[node].opr.idx - && str_idx == lim->subexp_to) - break; - } - if (node_idx == eclosures->nelem && str_idx == lim->subexp_to) - pos = 1; - } - return pos; -} - -/* Check the limitations of sub expressions LIMITS, and remove the nodes - which are against limitations from DEST_NODES. */ - -static reg_errcode_t -check_subexp_limits (dfa, dest_nodes, candidates, limits, bkref_ents, str_idx) - re_dfa_t *dfa; - re_node_set *dest_nodes; - const re_node_set *candidates; - re_node_set *limits; - struct re_backref_cache_entry *bkref_ents; - int str_idx; -{ - reg_errcode_t err; - int node_idx, lim_idx; - - for (lim_idx = 0; lim_idx < limits->nelem; ++lim_idx) - { - int bkref, subexp_idx; - struct re_backref_cache_entry *ent; - ent = bkref_ents + limits->elems[lim_idx]; - - if (str_idx <= ent->subexp_from || ent->str_idx < str_idx) - continue; /* This is unrelated limitation. */ - - bkref = (dfa->nodes[ent->node].type == OP_CONTEXT_NODE - ? dfa->nodes[ent->node].opr.ctx_info->entity : ent->node); - subexp_idx = dfa->nodes[bkref].opr.idx - 1; - - if (ent->subexp_to == str_idx) - { - int ops_node = -1; - int cls_node = -1; - for (node_idx = 0; node_idx < dest_nodes->nelem; ++node_idx) - { - int node = dest_nodes->elems[node_idx]; - re_token_type_t type= dfa->nodes[node].type; - if (type == OP_OPEN_SUBEXP - && subexp_idx == dfa->nodes[node].opr.idx) - ops_node = node; - else if (type == OP_CLOSE_SUBEXP - && subexp_idx == dfa->nodes[node].opr.idx) - cls_node = node; - } - - /* Check the limitation of the open subexpression. */ - /* Note that (ent->subexp_to = str_idx != ent->subexp_from). */ - if (ops_node >= 0) - { - err = sub_epsilon_src_nodes(dfa, ops_node, dest_nodes, - candidates); - if (BE (err != REG_NOERROR, 0)) - return err; - } - /* Check the limitation of the close subexpression. */ - for (node_idx = 0; node_idx < dest_nodes->nelem; ++node_idx) - { - int node = dest_nodes->elems[node_idx]; - if (!re_node_set_contains (dfa->inveclosures + node, cls_node) - && !re_node_set_contains (dfa->eclosures + node, cls_node)) - { - /* It is against this limitation. - Remove it form the current sifted state. */ - err = sub_epsilon_src_nodes(dfa, node, dest_nodes, - candidates); - if (BE (err != REG_NOERROR, 0)) - return err; - --node_idx; - } - } - } - else /* (ent->subexp_to != str_idx) */ - { - for (node_idx = 0; node_idx < dest_nodes->nelem; ++node_idx) - { - int node = dest_nodes->elems[node_idx]; - re_token_type_t type= dfa->nodes[node].type; - if (type == OP_CLOSE_SUBEXP || type == OP_OPEN_SUBEXP) - { - if (subexp_idx != dfa->nodes[node].opr.idx) - continue; - if ((type == OP_CLOSE_SUBEXP && ent->subexp_to != str_idx) - || (type == OP_OPEN_SUBEXP)) - { - /* It is against this limitation. - Remove it form the current sifted state. */ - err = sub_epsilon_src_nodes(dfa, node, dest_nodes, - candidates); - if (BE (err != REG_NOERROR, 0)) - return err; - } - } - } - } - } - return REG_NOERROR; -} - -/* Search for the top (in case of sctx->check_subexp < 0) or the - bottom (in case of sctx->check_subexp > 0) of the subexpressions - which the backreference sctx->cur_bkref can match. */ - -static reg_errcode_t -search_subexp (preg, mctx, sctx, str_idx, dest_nodes) - const regex_t *preg; - re_match_context_t *mctx; - re_sift_context_t *sctx; - int str_idx; - re_node_set *dest_nodes; -{ - reg_errcode_t err; - re_dfa_t *dfa = (re_dfa_t *)preg->buffer; - re_sift_context_t local_sctx; - int node_idx, node=0; /* gnupg */ - const re_node_set *candidates; - re_dfastate_t **lim_states = NULL; - candidates = ((mctx->state_log[str_idx] == NULL) ? &empty_set - : &mctx->state_log[str_idx]->nodes); - local_sctx.sifted_states = NULL; /* Mark that it hasn't been initialized. */ - - for (node_idx = 0; node_idx < dest_nodes->nelem; ++node_idx) - { - re_token_type_t type; - int entity; - node = dest_nodes->elems[node_idx]; - type = dfa->nodes[node].type; - entity = (type != OP_CONTEXT_NODE ? node - : dfa->nodes[node].opr.ctx_info->entity); - type = (type != OP_CONTEXT_NODE ? type : dfa->nodes[entity].type); - - if (type == OP_CLOSE_SUBEXP - && sctx->check_subexp == dfa->nodes[node].opr.idx + 1) - { - re_dfastate_t *cur_state; - /* Found the bottom of the subexpression, then search for the - top of it. */ - if (local_sctx.sifted_states == NULL) - { - /* It hasn't been initialized yet, initialize it now. */ - local_sctx = *sctx; - err = re_node_set_init_copy (&local_sctx.limits, &sctx->limits); - if (BE (err != REG_NOERROR, 0)) - return err; - } - local_sctx.check_subexp = -sctx->check_subexp; - local_sctx.limited_states = sctx->limited_states; - local_sctx.last_node = node; - local_sctx.last_str_idx = local_sctx.cls_subexp_idx = str_idx; - cur_state = local_sctx.sifted_states[str_idx]; - err = sift_states_backward (preg, mctx, &local_sctx); - local_sctx.sifted_states[str_idx] = cur_state; - if (BE (err != REG_NOERROR, 0)) - return err; - /* There must not 2 same node in a node set. */ - break; - } - else if (type == OP_OPEN_SUBEXP - && -sctx->check_subexp == dfa->nodes[node].opr.idx + 1) - { - /* Found the top of the subexpression, check that the - backreference can match the input string. */ - char *buf; - int dest_str_idx; - int bkref_str_idx = re_string_cur_idx (mctx->input); - int subexp_len = sctx->cls_subexp_idx - str_idx; - if (subexp_len < 0 || bkref_str_idx + subexp_len > mctx->input->len) - break; - - if (bkref_str_idx + subexp_len > mctx->input->valid_len - && mctx->input->valid_len < mctx->input->len) - { - reg_errcode_t err; - err = extend_buffers (mctx); - if (BE (err != REG_NOERROR, 0)) - return err; - } - buf = (char *) re_string_get_buffer (mctx->input); - if (strncmp (buf + str_idx, buf + bkref_str_idx, subexp_len) != 0) - break; - - if (sctx->limits.nelem && str_idx > 0) - { - re_dfastate_t *cur_state = sctx->sifted_states[str_idx]; - if (lim_states == NULL) - { - lim_states = re_malloc (re_dfastate_t *, str_idx + 1); - } - if (local_sctx.sifted_states == NULL) - { - /* It hasn't been initialized yet, initialize it now. */ - local_sctx = *sctx; - if (BE (lim_states == NULL, 0)) - return REG_ESPACE; - err = re_node_set_init_copy (&local_sctx.limits, - &sctx->limits); - if (BE (err != REG_NOERROR, 0)) - return err; - } - local_sctx.check_subexp = 0; - local_sctx.last_node = node; - local_sctx.last_str_idx = str_idx; - local_sctx.limited_states = lim_states; - memset (lim_states, '\0', - sizeof (re_dfastate_t*) * (str_idx + 1)); - err = sift_states_backward (preg, mctx, &local_sctx); - if (BE (err != REG_NOERROR, 0)) - return err; - if (local_sctx.sifted_states[0] == NULL - && local_sctx.limited_states[0] == NULL) - { - sctx->sifted_states[str_idx] = cur_state; - break; - } - sctx->sifted_states[str_idx] = cur_state; - } - /* Successfully matched, add a new cache entry. */ - dest_str_idx = bkref_str_idx + subexp_len; - err = match_ctx_add_entry (mctx, sctx->cur_bkref, bkref_str_idx, - str_idx, sctx->cls_subexp_idx); - if (BE (err != REG_NOERROR, 0)) - return err; - err = clean_state_log_if_need (mctx, dest_str_idx); - if (BE (err != REG_NOERROR, 0)) - return err; - break; - } - } - - /* Remove the top/bottom of the sub expression we processed. */ - if (node_idx < dest_nodes->nelem) - { - err = sub_epsilon_src_nodes(dfa, node, dest_nodes, candidates); - if (BE (err != REG_NOERROR, 0)) - return err; - /* Update state_log. */ - sctx->sifted_states[str_idx] = re_acquire_state (&err, dfa, dest_nodes); - if (BE (err != REG_NOERROR, 0)) - return err; - } - - if (local_sctx.sifted_states != NULL) - re_node_set_free (&local_sctx.limits); - if (lim_states != NULL) - re_free (lim_states); - return REG_NOERROR; -} - -static reg_errcode_t -sift_states_bkref (preg, mctx, sctx, str_idx, dest_nodes) - const regex_t *preg; - re_match_context_t *mctx; - re_sift_context_t *sctx; - int str_idx; - re_node_set *dest_nodes; -{ - reg_errcode_t err; - re_dfa_t *dfa = (re_dfa_t *)preg->buffer; - int node_idx, node; - re_sift_context_t local_sctx; - const re_node_set *candidates; - candidates = ((mctx->state_log[str_idx] == NULL) ? &empty_set - : &mctx->state_log[str_idx]->nodes); - local_sctx.sifted_states = NULL; /* Mark that it hasn't been initialized. */ - - for (node_idx = 0; node_idx < candidates->nelem; ++node_idx) - { - int entity; - int cur_bkref_idx = re_string_cur_idx (mctx->input); - re_token_type_t type; - node = candidates->elems[node_idx]; - type = dfa->nodes[node].type; - entity = (type != OP_CONTEXT_NODE ? node - : dfa->nodes[node].opr.ctx_info->entity); - type = (type != OP_CONTEXT_NODE ? type : dfa->nodes[entity].type); - if (node == sctx->cur_bkref && str_idx == cur_bkref_idx) - continue; - /* Avoid infinite loop for the REs like "()\1+". */ - if (node == sctx->last_node && str_idx == sctx->last_str_idx) - continue; - if (type == OP_BACK_REF) - { - int enabled_idx; - for (enabled_idx = 0; enabled_idx < mctx->nbkref_ents; ++enabled_idx) - { - int disabled_idx, subexp_len, to_idx; - struct re_backref_cache_entry *entry; - entry = mctx->bkref_ents + enabled_idx; - subexp_len = entry->subexp_to - entry->subexp_from; - to_idx = str_idx + subexp_len; - - if (entry->node != node || entry->str_idx != str_idx - || to_idx > sctx->last_str_idx - || sctx->sifted_states[to_idx] == NULL) - continue; - if (!STATE_NODE_CONTAINS (sctx->sifted_states[to_idx], - dfa->nexts[node])) - { - int dst_idx; - re_node_set *dsts = &sctx->sifted_states[to_idx]->nodes; - for (dst_idx = 0; dst_idx < dsts->nelem; ++dst_idx) - { - int dst_node = dsts->elems[dst_idx]; - if (dfa->nodes[dst_node].type == OP_CONTEXT_NODE - && (dfa->nodes[dst_node].opr.ctx_info->entity - == dfa->nexts[node])) - break; - } - if (dst_idx == dsts->nelem) - continue; - } - - if (check_dst_limits (dfa, &sctx->limits, mctx, node, - str_idx, dfa->nexts[node], to_idx)) - continue; - if (sctx->check_subexp == dfa->nodes[entity].opr.idx) - { - char *buf; - buf = (char *) re_string_get_buffer (mctx->input); - if (strncmp (buf + entry->subexp_from, - buf + cur_bkref_idx, subexp_len) != 0) - continue; - err = match_ctx_add_entry (mctx, sctx->cur_bkref, - cur_bkref_idx, entry->subexp_from, - entry->subexp_to); - if (BE (err != REG_NOERROR, 0)) - return err; - err = clean_state_log_if_need (mctx, cur_bkref_idx - + subexp_len); - if (BE (err != REG_NOERROR, 0)) - return err; - } - else - { - re_dfastate_t *cur_state; - entry->flag = 0; - for (disabled_idx = enabled_idx + 1; - disabled_idx < mctx->nbkref_ents; ++disabled_idx) - { - struct re_backref_cache_entry *entry2; - entry2 = mctx->bkref_ents + disabled_idx; - if (entry2->node != node || entry2->str_idx != str_idx) - continue; - entry2->flag = 1; - } - - if (local_sctx.sifted_states == NULL) - { - local_sctx = *sctx; - err = re_node_set_init_copy (&local_sctx.limits, - &sctx->limits); - if (BE (err != REG_NOERROR, 0)) - return err; - } - local_sctx.last_node = node; - local_sctx.last_str_idx = str_idx; - err = re_node_set_insert (&local_sctx.limits, enabled_idx); - if (BE (err < 0, 0)) - return REG_ESPACE; - cur_state = local_sctx.sifted_states[str_idx]; - err = sift_states_backward (preg, mctx, &local_sctx); - if (BE (err != REG_NOERROR, 0)) - return err; - if (sctx->limited_states != NULL) - { - err = merge_state_array (dfa, sctx->limited_states, - local_sctx.sifted_states, - str_idx + 1); - if (BE (err != REG_NOERROR, 0)) - return err; - } - local_sctx.sifted_states[str_idx] = cur_state; - re_node_set_remove_at (&local_sctx.limits, - local_sctx.limits.nelem - 1); - entry->flag = 1; - } - } - for (enabled_idx = 0; enabled_idx < mctx->nbkref_ents; ++enabled_idx) - { - struct re_backref_cache_entry *entry; - entry = mctx->bkref_ents + enabled_idx; - if (entry->node == node && entry->str_idx == str_idx) - entry->flag = 0; - } - } - } - if (local_sctx.sifted_states != NULL) - { - re_node_set_free (&local_sctx.limits); - } - - return REG_NOERROR; -} - - -#ifdef RE_ENABLE_I18N -static int -sift_states_iter_mb (preg, mctx, sctx, node_idx, str_idx, max_str_idx) - const regex_t *preg; - const re_match_context_t *mctx; - re_sift_context_t *sctx; - int node_idx, str_idx, max_str_idx; -{ - re_dfa_t *dfa = (re_dfa_t *) preg->buffer; - int naccepted; - /* Check the node can accept `multi byte'. */ - naccepted = check_node_accept_bytes (preg, node_idx, mctx->input, str_idx); - if (naccepted > 0 && str_idx + naccepted <= max_str_idx && - !STATE_NODE_CONTAINS (sctx->sifted_states[str_idx + naccepted], - dfa->nexts[node_idx])) - /* The node can't accept the `multi byte', or the - destination was already throwed away, then the node - could't accept the current input `multi byte'. */ - naccepted = 0; - /* Otherwise, it is sure that the node could accept - `naccepted' bytes input. */ - return naccepted; -} -#endif /* RE_ENABLE_I18N */ - - -/* Functions for state transition. */ - -/* Return the next state to which the current state STATE will transit by - accepting the current input byte, and update STATE_LOG if necessary. - If STATE can accept a multibyte char/collating element/back reference - update the destination of STATE_LOG. */ - -static re_dfastate_t * -transit_state (err, preg, mctx, state, fl_search) - reg_errcode_t *err; - const regex_t *preg; - re_match_context_t *mctx; - re_dfastate_t *state; - int fl_search; -{ - re_dfa_t *dfa = (re_dfa_t *) preg->buffer; - re_dfastate_t **trtable, *next_state; - unsigned char ch; - - if (re_string_cur_idx (mctx->input) + 1 >= mctx->input->bufs_len - || (re_string_cur_idx (mctx->input) + 1 >= mctx->input->valid_len - && mctx->input->valid_len < mctx->input->len)) - { - *err = extend_buffers (mctx); - if (BE (*err != REG_NOERROR, 0)) - return NULL; - } - - *err = REG_NOERROR; - if (state == NULL) - { - next_state = state; - re_string_skip_bytes (mctx->input, 1); - } - else - { -#ifdef RE_ENABLE_I18N - /* If the current state can accept multibyte. */ - if (state->accept_mb) - { - *err = transit_state_mb (preg, state, mctx); - if (BE (*err != REG_NOERROR, 0)) - return NULL; - } -#endif /* RE_ENABLE_I18N */ - - /* Then decide the next state with the single byte. */ - if (1) - { - /* Use transition table */ - ch = re_string_fetch_byte (mctx->input); - trtable = fl_search ? state->trtable_search : state->trtable; - if (trtable == NULL) - { - trtable = build_trtable (preg, state, fl_search); - if (fl_search) - state->trtable_search = trtable; - else - state->trtable = trtable; - } - next_state = trtable[ch]; - } - else - { - /* don't use transition table */ - next_state = transit_state_sb (err, preg, state, fl_search, mctx); - if (BE (next_state == NULL && err != REG_NOERROR, 0)) - return NULL; - } - } - - /* Update the state_log if we need. */ - if (mctx->state_log != NULL) - { - int cur_idx = re_string_cur_idx (mctx->input); - if (cur_idx > mctx->state_log_top) - { - mctx->state_log[cur_idx] = next_state; - mctx->state_log_top = cur_idx; - } - else if (mctx->state_log[cur_idx] == 0) - { - mctx->state_log[cur_idx] = next_state; - } - else - { - re_dfastate_t *pstate; - unsigned int context; - re_node_set next_nodes, *log_nodes, *table_nodes = NULL; - /* If (state_log[cur_idx] != 0), it implies that cur_idx is - the destination of a multibyte char/collating element/ - back reference. Then the next state is the union set of - these destinations and the results of the transition table. */ - pstate = mctx->state_log[cur_idx]; - log_nodes = pstate->entrance_nodes; - if (next_state != NULL) - { - table_nodes = next_state->entrance_nodes; - *err = re_node_set_init_union (&next_nodes, table_nodes, - log_nodes); - if (BE (*err != REG_NOERROR, 0)) - return NULL; - } - else - next_nodes = *log_nodes; - /* Note: We already add the nodes of the initial state, - then we don't need to add them here. */ - - context = re_string_context_at (mctx->input, - re_string_cur_idx (mctx->input) - 1, - mctx->eflags, preg->newline_anchor); - next_state = mctx->state_log[cur_idx] - = re_acquire_state_context (err, dfa, &next_nodes, context); - /* We don't need to check errors here, since the return value of - this function is next_state and ERR is already set. */ - - if (table_nodes != NULL) - re_node_set_free (&next_nodes); - } - /* If the next state has back references. */ - if (next_state != NULL && next_state->has_backref) - { - *err = transit_state_bkref (preg, next_state, mctx); - if (BE (*err != REG_NOERROR, 0)) - return NULL; - next_state = mctx->state_log[cur_idx]; - } - } - return next_state; -} - -/* Helper functions for transit_state. */ - -/* Return the next state to which the current state STATE will transit by - accepting the current input byte. */ - -static re_dfastate_t * -transit_state_sb (err, preg, state, fl_search, mctx) - reg_errcode_t *err; - const regex_t *preg; - re_dfastate_t *state; - int fl_search; - re_match_context_t *mctx; -{ - re_dfa_t *dfa = (re_dfa_t *) preg->buffer; - re_node_set next_nodes; - re_dfastate_t *next_state; - int node_cnt, cur_str_idx = re_string_cur_idx (mctx->input); - unsigned int context; - - *err = re_node_set_alloc (&next_nodes, state->nodes.nelem + 1); - if (BE (*err != REG_NOERROR, 0)) - return NULL; - for (node_cnt = 0; node_cnt < state->nodes.nelem; ++node_cnt) - { - int cur_node = state->nodes.elems[node_cnt]; - if (check_node_accept (preg, dfa->nodes + cur_node, mctx, cur_str_idx)) - { - *err = re_node_set_merge (&next_nodes, - dfa->eclosures + dfa->nexts[cur_node]); - if (BE (*err != REG_NOERROR, 0)) - return NULL; - } - } - if (fl_search) - { -#ifdef RE_ENABLE_I18N - int not_initial = 0; - if (MB_CUR_MAX > 1) - for (node_cnt = 0; node_cnt < next_nodes.nelem; ++node_cnt) - if (dfa->nodes[next_nodes.elems[node_cnt]].type == CHARACTER) - { - not_initial = dfa->nodes[next_nodes.elems[node_cnt]].mb_partial; - break; - } - if (!not_initial) -#endif - { - *err = re_node_set_merge (&next_nodes, - dfa->init_state->entrance_nodes); - if (BE (*err != REG_NOERROR, 0)) - return NULL; - } - } - context = re_string_context_at (mctx->input, cur_str_idx, mctx->eflags, - preg->newline_anchor); - next_state = re_acquire_state_context (err, dfa, &next_nodes, context); - /* We don't need to check errors here, since the return value of - this function is next_state and ERR is already set. */ - - re_node_set_free (&next_nodes); - re_string_skip_bytes (mctx->input, 1); - return next_state; -} - -#ifdef RE_ENABLE_I18N -static reg_errcode_t -transit_state_mb (preg, pstate, mctx) - const regex_t *preg; - re_dfastate_t *pstate; - re_match_context_t *mctx; -{ - reg_errcode_t err; - re_dfa_t *dfa = (re_dfa_t *) preg->buffer; - int i; - - for (i = 0; i < pstate->nodes.nelem; ++i) - { - re_node_set dest_nodes, *new_nodes; - int cur_node_idx = pstate->nodes.elems[i]; - int naccepted = 0, dest_idx; - unsigned int context; - re_dfastate_t *dest_state; - - if (dfa->nodes[cur_node_idx].type == OP_CONTEXT_NODE) - { - context = re_string_context_at (mctx->input, - re_string_cur_idx (mctx->input), - mctx->eflags, preg->newline_anchor); - if (NOT_SATISFY_NEXT_CONSTRAINT (dfa->nodes[cur_node_idx].constraint, - context)) - continue; - cur_node_idx = dfa->nodes[cur_node_idx].opr.ctx_info->entity; - } - - /* How many bytes the node can accepts? */ - if (ACCEPT_MB_NODE (dfa->nodes[cur_node_idx].type)) - naccepted = check_node_accept_bytes (preg, cur_node_idx, mctx->input, - re_string_cur_idx (mctx->input)); - if (naccepted == 0) - continue; - - /* The node can accepts `naccepted' bytes. */ - dest_idx = re_string_cur_idx (mctx->input) + naccepted; - mctx->max_mb_elem_len = ((mctx->max_mb_elem_len < naccepted) ? naccepted - : mctx->max_mb_elem_len); - err = clean_state_log_if_need (mctx, dest_idx); - if (BE (err != REG_NOERROR, 0)) - return err; -#ifdef DEBUG - assert (dfa->nexts[cur_node_idx] != -1); -#endif - /* `cur_node_idx' may point the entity of the OP_CONTEXT_NODE, - then we use pstate->nodes.elems[i] instead. */ - new_nodes = dfa->eclosures + dfa->nexts[pstate->nodes.elems[i]]; - - dest_state = mctx->state_log[dest_idx]; - if (dest_state == NULL) - dest_nodes = *new_nodes; - else - { - err = re_node_set_init_union (&dest_nodes, - dest_state->entrance_nodes, new_nodes); - if (BE (err != REG_NOERROR, 0)) - return err; - } - context = re_string_context_at (mctx->input, dest_idx - 1, mctx->eflags, - preg->newline_anchor); - mctx->state_log[dest_idx] - = re_acquire_state_context (&err, dfa, &dest_nodes, context); - if (BE (mctx->state_log[dest_idx] == NULL && err != REG_NOERROR, 0)) - return err; - if (dest_state != NULL) - re_node_set_free (&dest_nodes); - } - return REG_NOERROR; -} -#endif /* RE_ENABLE_I18N */ - -static reg_errcode_t -transit_state_bkref (preg, pstate, mctx) - const regex_t *preg; - re_dfastate_t *pstate; - re_match_context_t *mctx; -{ - reg_errcode_t err; - re_dfastate_t **work_state_log; - - work_state_log = re_malloc (re_dfastate_t *, - re_string_cur_idx (mctx->input) + 1); - if (BE (work_state_log == NULL, 0)) - return REG_ESPACE; - - err = transit_state_bkref_loop (preg, &pstate->nodes, work_state_log, mctx); - re_free (work_state_log); - return err; -} - -/* Caller must allocate `work_state_log'. */ - -static reg_errcode_t -transit_state_bkref_loop (preg, nodes, work_state_log, mctx) - const regex_t *preg; - re_node_set *nodes; - re_dfastate_t **work_state_log; - re_match_context_t *mctx; -{ - reg_errcode_t err; - re_dfa_t *dfa = (re_dfa_t *) preg->buffer; - int i; - regmatch_t *cur_regs = re_malloc (regmatch_t, preg->re_nsub + 1); - int cur_str_idx = re_string_cur_idx (mctx->input); - if (BE (cur_regs == NULL, 0)) - return REG_ESPACE; - - for (i = 0; i < nodes->nelem; ++i) - { - int dest_str_idx, subexp_idx, prev_nelem, bkc_idx; - int node_idx = nodes->elems[i]; - unsigned int context; - re_token_t *node = dfa->nodes + node_idx; - re_node_set *new_dest_nodes; - re_sift_context_t sctx; - - /* Check whether `node' is a backreference or not. */ - if (node->type == OP_BACK_REF) - subexp_idx = node->opr.idx; - else if (node->type == OP_CONTEXT_NODE && - dfa->nodes[node->opr.ctx_info->entity].type == OP_BACK_REF) - { - context = re_string_context_at (mctx->input, cur_str_idx, - mctx->eflags, preg->newline_anchor); - if (NOT_SATISFY_NEXT_CONSTRAINT (node->constraint, context)) - continue; - subexp_idx = dfa->nodes[node->opr.ctx_info->entity].opr.idx; - } - else - continue; - - /* `node' is a backreference. - Check the substring which the substring matched. */ - sift_ctx_init (&sctx, work_state_log, NULL, node_idx, cur_str_idx, - subexp_idx); - sctx.cur_bkref = node_idx; - match_ctx_clear_flag (mctx); - err = sift_states_backward (preg, mctx, &sctx); - if (BE (err != REG_NOERROR, 0)) - return err; - - /* And add the epsilon closures (which is `new_dest_nodes') of - the backreference to appropriate state_log. */ -#ifdef DEBUG - assert (dfa->nexts[node_idx] != -1); -#endif - for (bkc_idx = 0; bkc_idx < mctx->nbkref_ents; ++bkc_idx) - { - int subexp_len; - re_dfastate_t *dest_state; - struct re_backref_cache_entry *bkref_ent; - bkref_ent = mctx->bkref_ents + bkc_idx; - if (bkref_ent->node != node_idx || bkref_ent->str_idx != cur_str_idx) - continue; - subexp_len = bkref_ent->subexp_to - bkref_ent->subexp_from; - new_dest_nodes = ((node->type == OP_CONTEXT_NODE && subexp_len == 0) - ? dfa->nodes[node_idx].opr.ctx_info->bkref_eclosure - : dfa->eclosures + dfa->nexts[node_idx]); - dest_str_idx = (cur_str_idx + bkref_ent->subexp_to - - bkref_ent->subexp_from); - context = (IS_WORD_CHAR (re_string_byte_at (mctx->input, - dest_str_idx - 1)) - ? CONTEXT_WORD : 0); - dest_state = mctx->state_log[dest_str_idx]; - prev_nelem = ((mctx->state_log[cur_str_idx] == NULL) ? 0 - : mctx->state_log[cur_str_idx]->nodes.nelem); - /* Add `new_dest_node' to state_log. */ - if (dest_state == NULL) - { - mctx->state_log[dest_str_idx] - = re_acquire_state_context (&err, dfa, new_dest_nodes, - context); - if (BE (mctx->state_log[dest_str_idx] == NULL - && err != REG_NOERROR, 0)) - return err; - } - else - { - re_node_set dest_nodes; - err = re_node_set_init_union (&dest_nodes, - dest_state->entrance_nodes, - new_dest_nodes); - if (BE (err != REG_NOERROR, 0)) - return err; - mctx->state_log[dest_str_idx] - = re_acquire_state_context (&err, dfa, &dest_nodes, context); - if (BE (mctx->state_log[dest_str_idx] == NULL - && err != REG_NOERROR, 0)) - return err; - re_node_set_free (&dest_nodes); - } - /* We need to check recursively if the backreference can epsilon - transit. */ - if (subexp_len == 0 - && mctx->state_log[cur_str_idx]->nodes.nelem > prev_nelem) - { - err = transit_state_bkref_loop (preg, new_dest_nodes, - work_state_log, mctx); - if (BE (err != REG_NOERROR, 0)) - return err; - } - } - } - re_free (cur_regs); - return REG_NOERROR; -} - -/* Build transition table for the state. - Return the new table if succeeded, otherwise return NULL. */ - -static re_dfastate_t ** -build_trtable (preg, state, fl_search) - const regex_t *preg; - const re_dfastate_t *state; - int fl_search; -{ - reg_errcode_t err; - re_dfa_t *dfa = (re_dfa_t *) preg->buffer; - int i, j, k, ch; - int ndests; /* Number of the destination states from `state'. */ - re_dfastate_t **trtable, **dest_states, **dest_states_word, **dest_states_nl; - re_node_set follows, *dests_node; - bitset *dests_ch; - bitset acceptable; - - /* We build DFA states which corresponds to the destination nodes - from `state'. `dests_node[i]' represents the nodes which i-th - destination state contains, and `dests_ch[i]' represents the - characters which i-th destination state accepts. */ - dests_node = re_malloc (re_node_set, SBC_MAX); - dests_ch = re_malloc (bitset, SBC_MAX); - - /* Initialize transiton table. */ - trtable = (re_dfastate_t **) calloc (sizeof (re_dfastate_t *), SBC_MAX); - if (BE (dests_node == NULL || dests_ch == NULL || trtable == NULL, 0)) - return NULL; - - /* At first, group all nodes belonging to `state' into several - destinations. */ - ndests = group_nodes_into_DFAstates (preg, state, dests_node, dests_ch); - if (BE (ndests <= 0, 0)) - { - re_free (dests_node); - re_free (dests_ch); - /* Return NULL in case of an error, trtable otherwise. */ - return (ndests < 0) ? NULL : trtable; - } - - dest_states = re_malloc (re_dfastate_t *, ndests); - dest_states_word = re_malloc (re_dfastate_t *, ndests); - dest_states_nl = re_malloc (re_dfastate_t *, ndests); - bitset_empty (acceptable); - - err = re_node_set_alloc (&follows, ndests + 1); - if (BE (dest_states == NULL || dest_states_word == NULL - || dest_states_nl == NULL || err != REG_NOERROR, 0)) - return NULL; - - /* Then build the states for all destinations. */ - for (i = 0; i < ndests; ++i) - { - int next_node; - re_node_set_empty (&follows); - /* Merge the follows of this destination states. */ - for (j = 0; j < dests_node[i].nelem; ++j) - { - next_node = dfa->nexts[dests_node[i].elems[j]]; - if (next_node != -1) - { - err = re_node_set_merge (&follows, dfa->eclosures + next_node); - if (BE (err != REG_NOERROR, 0)) - return NULL; - } - } - /* If search flag is set, merge the initial state. */ - if (fl_search) - { -#ifdef RE_ENABLE_I18N - int not_initial = 0; - for (j = 0; j < follows.nelem; ++j) - if (dfa->nodes[follows.elems[j]].type == CHARACTER) - { - not_initial = dfa->nodes[follows.elems[j]].mb_partial; - break; - } - if (!not_initial) -#endif - { - err = re_node_set_merge (&follows, - dfa->init_state->entrance_nodes); - if (BE (err != REG_NOERROR, 0)) - return NULL; - } - } - dest_states[i] = re_acquire_state_context (&err, dfa, &follows, 0); - if (BE (dest_states[i] == NULL && err != REG_NOERROR, 0)) - return NULL; - /* If the new state has context constraint, - build appropriate states for these contexts. */ - if (dest_states[i]->has_constraint) - { - dest_states_word[i] = re_acquire_state_context (&err, dfa, &follows, - CONTEXT_WORD); - if (BE (dest_states_word[i] == NULL && err != REG_NOERROR, 0)) - return NULL; - dest_states_nl[i] = re_acquire_state_context (&err, dfa, &follows, - CONTEXT_NEWLINE); - if (BE (dest_states_nl[i] == NULL && err != REG_NOERROR, 0)) - return NULL; - } - else - { - dest_states_word[i] = dest_states[i]; - dest_states_nl[i] = dest_states[i]; - } - bitset_merge (acceptable, dests_ch[i]); - } - - /* Update the transition table. */ - /* For all characters ch...: */ - for (i = 0, ch = 0; i < BITSET_UINTS; ++i) - for (j = 0; j < UINT_BITS; ++j, ++ch) - if ((acceptable[i] >> j) & 1) - { - /* The current state accepts the character ch. */ - if (IS_WORD_CHAR (ch)) - { - for (k = 0; k < ndests; ++k) - if ((dests_ch[k][i] >> j) & 1) - { - /* k-th destination accepts the word character ch. */ - trtable[ch] = dest_states_word[k]; - /* There must be only one destination which accepts - character ch. See group_nodes_into_DFAstates. */ - break; - } - } - else /* not WORD_CHAR */ - { - for (k = 0; k < ndests; ++k) - if ((dests_ch[k][i] >> j) & 1) - { - /* k-th destination accepts the non-word character ch. */ - trtable[ch] = dest_states[k]; - /* There must be only one destination which accepts - character ch. See group_nodes_into_DFAstates. */ - break; - } - } - } - /* new line */ - if (bitset_contain (acceptable, NEWLINE_CHAR)) - { - /* The current state accepts newline character. */ - for (k = 0; k < ndests; ++k) - if (bitset_contain (dests_ch[k], NEWLINE_CHAR)) - { - /* k-th destination accepts newline character. */ - trtable[NEWLINE_CHAR] = dest_states_nl[k]; - /* There must be only one destination which accepts - newline. See group_nodes_into_DFAstates. */ - break; - } - } - - re_free (dest_states_nl); - re_free (dest_states_word); - re_free (dest_states); - - re_node_set_free (&follows); - for (i = 0; i < ndests; ++i) - re_node_set_free (dests_node + i); - - re_free (dests_ch); - re_free (dests_node); - - return trtable; -} - -/* Group all nodes belonging to STATE into several destinations. - Then for all destinations, set the nodes belonging to the destination - to DESTS_NODE[i] and set the characters accepted by the destination - to DEST_CH[i]. This function return the number of destinations. */ - -static int -group_nodes_into_DFAstates (preg, state, dests_node, dests_ch) - const regex_t *preg; - const re_dfastate_t *state; - re_node_set *dests_node; - bitset *dests_ch; -{ - reg_errcode_t err; - const re_dfa_t *dfa = (re_dfa_t *) preg->buffer; - int i, j, k; - int ndests; /* Number of the destinations from `state'. */ - bitset accepts; /* Characters a node can accept. */ - const re_node_set *cur_nodes = &state->nodes; - bitset_empty (accepts); - ndests = 0; - - /* For all the nodes belonging to `state', */ - for (i = 0; i < cur_nodes->nelem; ++i) - { - unsigned int constraint = 0; - re_token_t *node = &dfa->nodes[cur_nodes->elems[i]]; - re_token_type_t type = node->type; - - if (type == OP_CONTEXT_NODE) - { - constraint = node->constraint; - node = dfa->nodes + node->opr.ctx_info->entity; - type = node->type; - } - - /* Enumerate all single byte character this node can accept. */ - if (type == CHARACTER) - bitset_set (accepts, node->opr.c); - else if (type == SIMPLE_BRACKET) - { - bitset_merge (accepts, node->opr.sbcset); - } - else if (type == OP_PERIOD) - { - bitset_set_all (accepts); - if (!(preg->syntax & RE_DOT_NEWLINE)) - bitset_clear (accepts, '\n'); - if (preg->syntax & RE_DOT_NOT_NULL) - bitset_clear (accepts, '\0'); - } - else - continue; - - /* Check the `accepts' and sift the characters which are not - match it the context. */ - if (constraint) - { - if (constraint & NEXT_WORD_CONSTRAINT) - for (j = 0; j < BITSET_UINTS; ++j) - accepts[j] &= dfa->word_char[j]; - else if (constraint & NEXT_NOTWORD_CONSTRAINT) - for (j = 0; j < BITSET_UINTS; ++j) - accepts[j] &= ~dfa->word_char[j]; - else if (constraint & NEXT_NEWLINE_CONSTRAINT) - { - int accepts_newline = bitset_contain (accepts, NEWLINE_CHAR); - bitset_empty (accepts); - if (accepts_newline) - bitset_set (accepts, NEWLINE_CHAR); - else - continue; - } - } - - /* Then divide `accepts' into DFA states, or create a new - state. */ - for (j = 0; j < ndests; ++j) - { - bitset intersec; /* Intersection sets, see below. */ - bitset remains; - /* Flags, see below. */ - int has_intersec, not_subset, not_consumed; - - /* Optimization, skip if this state doesn't accept the character. */ - if (type == CHARACTER && !bitset_contain (dests_ch[j], node->opr.c)) - continue; - - /* Enumerate the intersection set of this state and `accepts'. */ - has_intersec = 0; - for (k = 0; k < BITSET_UINTS; ++k) - has_intersec |= intersec[k] = accepts[k] & dests_ch[j][k]; - /* And skip if the intersection set is empty. */ - if (!has_intersec) - continue; - - /* Then check if this state is a subset of `accepts'. */ - not_subset = not_consumed = 0; - for (k = 0; k < BITSET_UINTS; ++k) - { - not_subset |= remains[k] = ~accepts[k] & dests_ch[j][k]; - not_consumed |= accepts[k] = accepts[k] & ~dests_ch[j][k]; - } - - /* If this state isn't a subset of `accepts', create a - new group state, which has the `remains'. */ - if (not_subset) - { - bitset_copy (dests_ch[ndests], remains); - bitset_copy (dests_ch[j], intersec); - err = re_node_set_init_copy (dests_node + ndests, &dests_node[j]); - if (BE (err != REG_NOERROR, 0)) - return -1; - ++ndests; - } - - /* Put the position in the current group. */ - err = re_node_set_insert (&dests_node[j], cur_nodes->elems[i]); - if (BE (err < 0, 0)) - return -1; - - /* If all characters are consumed, go to next node. */ - if (!not_consumed) - break; - } - /* Some characters remain, create a new group. */ - if (j == ndests) - { - bitset_copy (dests_ch[ndests], accepts); - err = re_node_set_init_1 (dests_node + ndests, cur_nodes->elems[i]); - if (BE (err != REG_NOERROR, 0)) - return -1; - ++ndests; - bitset_empty (accepts); - } - } - return ndests; -} - -#ifdef RE_ENABLE_I18N -/* Check how many bytes the node `dfa->nodes[node_idx]' accepts. - Return the number of the bytes the node accepts. - STR_IDX is the current index of the input string. - - This function handles the nodes which can accept one character, or - one collating element like '.', '[a-z]', opposite to the other nodes - can only accept one byte. */ - -static int -check_node_accept_bytes (preg, node_idx, input, str_idx) - const regex_t *preg; - int node_idx, str_idx; - const re_string_t *input; -{ - const re_dfa_t *dfa = (re_dfa_t *) preg->buffer; - const re_token_t *node = dfa->nodes + node_idx; - int elem_len = re_string_elem_size_at (input, str_idx); - int char_len = re_string_char_size_at (input, str_idx); - int i; -# ifdef _LIBC - int j; - uint32_t nrules = _NL_CURRENT_WORD (LC_COLLATE, _NL_COLLATE_NRULES); -# endif /* _LIBC */ - if (elem_len <= 1 && char_len <= 1) - return 0; - if (node->type == OP_PERIOD) - { - /* '.' accepts any one character except the following two cases. */ - if ((!(preg->syntax & RE_DOT_NEWLINE) && - re_string_byte_at (input, str_idx) == '\n') || - ((preg->syntax & RE_DOT_NOT_NULL) && - re_string_byte_at (input, str_idx) == '\0')) - return 0; - return char_len; - } - else if (node->type == COMPLEX_BRACKET) - { - const re_charset_t *cset = node->opr.mbcset; -# ifdef _LIBC - const unsigned char *pin = re_string_get_buffer (input) + str_idx; -# endif /* _LIBC */ - int match_len = 0; - wchar_t wc = ((cset->nranges || cset->nchar_classes || cset->nmbchars) - ? re_string_wchar_at (input, str_idx) : 0); - - /* match with multibyte character? */ - for (i = 0; i < cset->nmbchars; ++i) - if (wc == cset->mbchars[i]) - { - match_len = char_len; - goto check_node_accept_bytes_match; - } - /* match with character_class? */ - for (i = 0; i < cset->nchar_classes; ++i) - { - wctype_t wt = cset->char_classes[i]; - if (__iswctype (wc, wt)) - { - match_len = char_len; - goto check_node_accept_bytes_match; - } - } - -# ifdef _LIBC - if (nrules != 0) - { - unsigned int in_collseq = 0; - const int32_t *table, *indirect; - const unsigned char *weights, *extra; - const char *collseqwc; - int32_t idx; - /* This #include defines a local function! */ -# include <locale/weight.h> - - /* match with collating_symbol? */ - if (cset->ncoll_syms) - extra = (const unsigned char *) - _NL_CURRENT (LC_COLLATE, _NL_COLLATE_SYMB_EXTRAMB); - for (i = 0; i < cset->ncoll_syms; ++i) - { - const unsigned char *coll_sym = extra + cset->coll_syms[i]; - /* Compare the length of input collating element and - the length of current collating element. */ - if (*coll_sym != elem_len) - continue; - /* Compare each bytes. */ - for (j = 0; j < *coll_sym; j++) - if (pin[j] != coll_sym[1 + j]) - break; - if (j == *coll_sym) - { - /* Match if every bytes is equal. */ - match_len = j; - goto check_node_accept_bytes_match; - } - } - - if (cset->nranges) - { - if (elem_len <= char_len) - { - collseqwc = _NL_CURRENT (LC_COLLATE, _NL_COLLATE_COLLSEQWC); - in_collseq = collseq_table_lookup (collseqwc, wc); - } - else - in_collseq = find_collation_sequence_value (pin, elem_len); - } - /* match with range expression? */ - for (i = 0; i < cset->nranges; ++i) - if (cset->range_starts[i] <= in_collseq - && in_collseq <= cset->range_ends[i]) - { - match_len = elem_len; - goto check_node_accept_bytes_match; - } - - /* match with equivalence_class? */ - if (cset->nequiv_classes) - { - const unsigned char *cp = pin; - table = (const int32_t *) - _NL_CURRENT (LC_COLLATE, _NL_COLLATE_TABLEMB); - weights = (const unsigned char *) - _NL_CURRENT (LC_COLLATE, _NL_COLLATE_WEIGHTMB); - extra = (const unsigned char *) - _NL_CURRENT (LC_COLLATE, _NL_COLLATE_EXTRAMB); - indirect = (const int32_t *) - _NL_CURRENT (LC_COLLATE, _NL_COLLATE_INDIRECTMB); - idx = findidx (&cp); - if (idx > 0) - for (i = 0; i < cset->nequiv_classes; ++i) - { - int32_t equiv_class_idx = cset->equiv_classes[i]; - size_t weight_len = weights[idx]; - if (weight_len == weights[equiv_class_idx]) - { - int cnt = 0; - while (cnt <= weight_len - && (weights[equiv_class_idx + 1 + cnt] - == weights[idx + 1 + cnt])) - ++cnt; - if (cnt > weight_len) - { - match_len = elem_len; - goto check_node_accept_bytes_match; - } - } - } - } - } - else -# endif /* _LIBC */ - { - /* match with range expression? */ -#if __GNUC__ >= 2 - wchar_t cmp_buf[] = {L'\0', L'\0', wc, L'\0', L'\0', L'\0'}; -#else - wchar_t cmp_buf[] = {L'\0', L'\0', L'\0', L'\0', L'\0', L'\0'}; - cmp_buf[2] = wc; -#endif - for (i = 0; i < cset->nranges; ++i) - { - cmp_buf[0] = cset->range_starts[i]; - cmp_buf[4] = cset->range_ends[i]; - if (wcscoll (cmp_buf, cmp_buf + 2) <= 0 - && wcscoll (cmp_buf + 2, cmp_buf + 4) <= 0) - { - match_len = char_len; - goto check_node_accept_bytes_match; - } - } - } - check_node_accept_bytes_match: - if (!cset->non_match) - return match_len; - else - { - if (match_len > 0) - return 0; - else - return (elem_len > char_len) ? elem_len : char_len; - } - } - return 0; -} - -# ifdef _LIBC -static unsigned int -find_collation_sequence_value (mbs, mbs_len) - const unsigned char *mbs; - size_t mbs_len; -{ - uint32_t nrules = _NL_CURRENT_WORD (LC_COLLATE, _NL_COLLATE_NRULES); - if (nrules == 0) - { - if (mbs_len == 1) - { - /* No valid character. Match it as a single byte character. */ - const unsigned char *collseq = (const unsigned char *) - _NL_CURRENT (LC_COLLATE, _NL_COLLATE_COLLSEQMB); - return collseq[mbs[0]]; - } - return UINT_MAX; - } - else - { - int32_t idx; - const unsigned char *extra = (const unsigned char *) - _NL_CURRENT (LC_COLLATE, _NL_COLLATE_SYMB_EXTRAMB); - - for (idx = 0; ;) - { - int mbs_cnt, found = 0; - int32_t elem_mbs_len; - /* Skip the name of collating element name. */ - idx = idx + extra[idx] + 1; - elem_mbs_len = extra[idx++]; - if (mbs_len == elem_mbs_len) - { - for (mbs_cnt = 0; mbs_cnt < elem_mbs_len; ++mbs_cnt) - if (extra[idx + mbs_cnt] != mbs[mbs_cnt]) - break; - if (mbs_cnt == elem_mbs_len) - /* Found the entry. */ - found = 1; - } - /* Skip the byte sequence of the collating element. */ - idx += elem_mbs_len; - /* Adjust for the alignment. */ - idx = (idx + 3) & ~3; - /* Skip the collation sequence value. */ - idx += sizeof (uint32_t); - /* Skip the wide char sequence of the collating element. */ - idx = idx + sizeof (uint32_t) * (extra[idx] + 1); - /* If we found the entry, return the sequence value. */ - if (found) - return *(uint32_t *) (extra + idx); - /* Skip the collation sequence value. */ - idx += sizeof (uint32_t); - } - } -} -# endif /* _LIBC */ -#endif /* RE_ENABLE_I18N */ - -/* Check whether the node accepts the byte which is IDX-th - byte of the INPUT. */ - -static int -check_node_accept (preg, node, mctx, idx) - const regex_t *preg; - const re_token_t *node; - const re_match_context_t *mctx; - int idx; -{ - const re_dfa_t *dfa = (re_dfa_t *) preg->buffer; - const re_token_t *cur_node; - unsigned char ch; - if (node->type == OP_CONTEXT_NODE) - { - /* The node has constraints. Check whether the current context - satisfies the constraints. */ - unsigned int context = re_string_context_at (mctx->input, idx, - mctx->eflags, - preg->newline_anchor); - if (NOT_SATISFY_NEXT_CONSTRAINT (node->constraint, context)) - return 0; - cur_node = dfa->nodes + node->opr.ctx_info->entity; - } - else - cur_node = node; - - ch = re_string_byte_at (mctx->input, idx); - if (cur_node->type == CHARACTER) - return cur_node->opr.c == ch; - else if (cur_node->type == SIMPLE_BRACKET) - return bitset_contain (cur_node->opr.sbcset, ch); - else if (cur_node->type == OP_PERIOD) - return !((ch == '\n' && !(preg->syntax & RE_DOT_NEWLINE)) - || (ch == '\0' && (preg->syntax & RE_DOT_NOT_NULL))); - else - return 0; -} - -/* Extend the buffers, if the buffers have run out. */ - -static reg_errcode_t -extend_buffers (mctx) - re_match_context_t *mctx; -{ - reg_errcode_t ret; - re_string_t *pstr = mctx->input; - - /* Double the lengthes of the buffers. */ - ret = re_string_realloc_buffers (pstr, pstr->bufs_len * 2); - if (BE (ret != REG_NOERROR, 0)) - return ret; - - if (mctx->state_log != NULL) - { - /* And double the length of state_log. */ - mctx->state_log = re_realloc (mctx->state_log, re_dfastate_t *, - pstr->bufs_len * 2); - if (BE (mctx->state_log == NULL, 0)) - return REG_ESPACE; - } - - /* Then reconstruct the buffers. */ - if (pstr->icase) - { -#ifdef RE_ENABLE_I18N - if (MB_CUR_MAX > 1) - build_wcs_upper_buffer (pstr); - else -#endif /* RE_ENABLE_I18N */ - build_upper_buffer (pstr); - } - else - { -#ifdef RE_ENABLE_I18N - if (MB_CUR_MAX > 1) - build_wcs_buffer (pstr); - else -#endif /* RE_ENABLE_I18N */ - { - if (pstr->trans != NULL) - re_string_translate_buffer (pstr); - else - pstr->valid_len = pstr->bufs_len; - } - } - return REG_NOERROR; -} - - -/* Functions for matching context. */ - -static reg_errcode_t -match_ctx_init (mctx, eflags, input, n) - re_match_context_t *mctx; - int eflags, n; - re_string_t *input; -{ - mctx->eflags = eflags; - mctx->input = input; - mctx->match_last = -1; - if (n > 0) - { - mctx->bkref_ents = re_malloc (struct re_backref_cache_entry, n); - if (BE (mctx->bkref_ents == NULL, 0)) - return REG_ESPACE; - } - else - mctx->bkref_ents = NULL; - mctx->nbkref_ents = 0; - mctx->abkref_ents = n; - mctx->max_mb_elem_len = 0; - return REG_NOERROR; -} - -static void -match_ctx_free (mctx) - re_match_context_t *mctx; -{ - re_free (mctx->bkref_ents); -} - -/* Add a new backreference entry to the cache. */ - -static reg_errcode_t -match_ctx_add_entry (mctx, node, str_idx, from, to) - re_match_context_t *mctx; - int node, str_idx, from, to; -{ - if (mctx->nbkref_ents >= mctx->abkref_ents) - { - mctx->bkref_ents = re_realloc (mctx->bkref_ents, - struct re_backref_cache_entry, - mctx->abkref_ents * 2); - if (BE (mctx->bkref_ents == NULL, 0)) - return REG_ESPACE; - memset (mctx->bkref_ents + mctx->nbkref_ents, '\0', - sizeof (struct re_backref_cache_entry) * mctx->abkref_ents); - mctx->abkref_ents *= 2; - } - mctx->bkref_ents[mctx->nbkref_ents].node = node; - mctx->bkref_ents[mctx->nbkref_ents].str_idx = str_idx; - mctx->bkref_ents[mctx->nbkref_ents].subexp_from = from; - mctx->bkref_ents[mctx->nbkref_ents].subexp_to = to; - mctx->bkref_ents[mctx->nbkref_ents++].flag = 0; - if (mctx->max_mb_elem_len < to - from) - mctx->max_mb_elem_len = to - from; - return REG_NOERROR; -} - -static void -match_ctx_clear_flag (mctx) - re_match_context_t *mctx; -{ - int i; - for (i = 0; i < mctx->nbkref_ents; ++i) - { - mctx->bkref_ents[i].flag = 0; - } -} - -static void -sift_ctx_init (sctx, sifted_sts, limited_sts, last_node, last_str_idx, - check_subexp) - re_sift_context_t *sctx; - re_dfastate_t **sifted_sts, **limited_sts; - int last_node, last_str_idx, check_subexp; -{ - sctx->sifted_states = sifted_sts; - sctx->limited_states = limited_sts; - sctx->last_node = last_node; - sctx->last_str_idx = last_str_idx; - sctx->check_subexp = check_subexp; - re_node_set_init_empty (&sctx->limits); -} diff --git a/util/riscos.c b/util/riscos.c deleted file mode 100644 index b94ff5318..000000000 --- a/util/riscos.c +++ /dev/null @@ -1,436 +0,0 @@ -/* riscos.c - RISC OS stuff - * Copyright (C) 2001 Free Software Foundation, Inc. - * - * This file is part of GnuPG for RISC OS. - * - * GnuPG is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * GnuPG is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, - * USA. - */ - -#ifndef __RISCOS__C__ -#define __RISCOS__C__ - -#include <config.h> -#include <stdlib.h> -#include <string.h> -#include <signal.h> -#include <fcntl.h> -#include <unistd.h> -#include <errno.h> -#include <kernel.h> -#include <swis.h> -#include "util.h" -#include "memory.h" - -#include <unixlib/local.h> /* needed for RISCOSIFY_NO_PROCESS */ -#define __UNIXLIB_INTERNALS -#include <unixlib/swiparams.h> /* needed for MMM_TYPE_* definitions */ -#undef __UNIXLIB_INTERNALS - - -/* static symbols that trigger UnixLib behaviour */ - -int __riscosify_control = __RISCOSIFY_NO_PROCESS; -int __feature_imagefs_is_file = 1; - - -/* RISC OS file open descriptor control list */ - -struct fds_item { - int fd; - struct fds_item *next; -}; -static struct fds_item *fds_list = NULL; -static int fdlist_initialized = 0; - - -/* local RISC OS functions */ - -static int -is_read_only(const char *filename) -{ - int type, attr; - - if (_swix(OS_File, _INR(0,1) | _OUT(0) | _OUT(5), - 17, filename, &type, &attr)) - log_fatal("Can't get file attributes for file \"%s\"!\n", filename); - - if (type == 0) - log_fatal("Can't find file \"%s\"!\n", filename); - - if (_swix(OS_File, _INR(0,1) | _IN(5), 4, filename, attr)) - return 1; - - return 0; -} - -/* exported RISC OS functions */ - -int -riscos_load_module(const char *name, const char * const path[], int fatal) -{ - int i; - - /* Is module already loaded? */ - if (!_swix(OS_Module, _INR(0,1), 18, name)) - return 1; - - /* Check all the places where the module could be located */ - for (i=0; path[i]; ++i) - if (!_swix(OS_Module, _INR(0,1), 1, path[i])) - return 1; - - /* Can't find module in the default locations */ - if (fatal) - log_fatal("Operation cannot be performed without \"%s\" module!\n", - name); - else - log_info("Can't load \"%s\" module, continuing anyway!\n", name); - - return 0; -} - -int -riscos_get_filetype_from_string(const char *string, int len) -{ - int result = 0xfff; - - if (strlen(string) < 5 || string[len - 4] != ',') - return -1; - - sscanf(string+len-3, "%3x", &result); - - return result; -} - -int -riscos_get_filetype(const char *filename) -{ - int result; - - if (_swix(OS_File, _INR(0,1) | _OUT(2), 17, filename, &result)) - log_fatal("Can't get filetype for file \"%s\"!\n", filename); - - if ((result & 0xfff00000) == 0xfff00000) - return (result & 0xfff00) >> 8; - else - return 0; -} - -void -riscos_set_filetype_by_number(const char *filename, int type) -{ - if (_swix(OS_File, _INR(0,2), 18, filename, type)) - log_fatal("Can't set filetype for file \"%s\"!\n" - "Is the file on a read-only file system?\n", filename); -} - -void -riscos_set_filetype_by_mimetype(const char *filename, const char *mimetype) -{ - int result; - - if (_swix(MimeMap_Translate, _INR(0,2) | _OUT(3), - MMM_TYPE_MIME, mimetype, MMM_TYPE_RISCOS, &result)) - log_fatal("Can't translate MIME type \"%s\"!\n", mimetype); - - riscos_set_filetype_by_number(filename, result); -} - -pid_t -riscos_getpid(void) -{ - int state; - - if (_swix(Wimp_ReadSysInfo, _IN(0) | _OUT(0), 3, &state)) - log_fatal("Wimp_ReadSysInfo failed: Can't get WimpState (R0=3)!\n"); - - if (state) - if (_swix(Wimp_ReadSysInfo, _IN(0) | _OUT(0), 5, &state)) - log_fatal("Wimp_ReadSysInfo failed: " - "Can't get task handle (R0=5)!\n"); - - return (pid_t) state; -} - -int -riscos_kill(pid_t pid, int sig) -{ - int buf[4], iter = 0; - - if (sig) - kill(pid, sig); - - do { - if (_swix(TaskManager_EnumerateTasks, _INR(0,2) | _OUT(0), - iter, buf, 16, &iter)) - log_fatal("TaskManager_EnumerateTasks failed!\n"); - if (buf[0] == pid) - return 0; - } while (iter >= 0); - - return __set_errno(ESRCH); -} - -int -riscos_access(const char *path, int amode) -{ - /* Do additional check, i.e. whether path is on write-protected floppy */ - if ((amode & W_OK) && is_read_only(path)) - return 1; - return access(path, amode); -} - -int -riscos_getchar(void) -{ - int c, flags; - - if (_swix(OS_ReadC, _OUT(0) | _OUT(_FLAGS), &c, &flags)) - log_fatal("OS_ReadC failed: Couldn't read from keyboard!\n"); - if (flags & _C) - log_fatal("OS_ReadC failed: Return Code = %i!\n", c); - - return c; -} - -#ifdef DEBUG -void -riscos_dump_fdlist(void) -{ - struct fds_item *iter = fds_list; - printf("List of open file descriptors:\n"); - while (iter) { - printf(" %i\n", iter->fd); - iter = iter->next; - } -} -#endif /* DEBUG */ - -int -riscos_fdopenfile(const char *filename, const int allow_write) -{ - struct fds_item *h; - int fd; - if (allow_write) - fd = open(filename, O_CREAT | O_TRUNC | O_RDWR, S_IRUSR | S_IWUSR); - else - fd = open(filename, O_RDONLY); - if (fd == -1) - log_error("Can't open file \"%s\": %i, %s!\n", - filename, errno, strerror(errno)); - - if (!fdlist_initialized) { - atexit (riscos_close_fds); - fdlist_initialized = 1; - } - - h = fds_list; - fds_list = (struct fds_item *) xmalloc(sizeof(struct fds_item)); - if (!fds_list) - log_fatal("Can't claim memory for fdopenfile() buffer!\n"); - fds_list->fd = fd; - fds_list->next = h; - - return fd; -} - -void -riscos_close_fds(void) -{ - FILE *fp; - struct fds_item *h = fds_list; - while( fds_list ) { - h = fds_list->next; - fp = fdopen (fds_list->fd, "a"); - if (fp) - fflush(fp); - close(fds_list->fd); - xfree(fds_list); - fds_list = h; - } -} - -int -riscos_renamefile(const char *old, const char *new) -{ - _kernel_oserror *e; - - if (e = _swix(OS_FSControl, _INR(0,2), 25, old, new)) { - if (e->errnum == 214) - return __set_errno(ENOENT); - if (e->errnum == 176) - return __set_errno(EEXIST); - printf("Error during renaming: %i, %s!\n", e->errnum, e->errmess); - return __set_errno(EOPSYS); - } - return 0; -} - -char * -riscos_gstrans(const char *old) -{ - int size = 256, last; - char *buf, *tmp; - - buf = (char *) xmalloc(size); - if (!buf) - log_fatal("Can't claim memory for OS_GSTrans buffer!\n"); - while (_C & _swi(OS_GSTrans, _INR(0,2) | _OUT(2) | _RETURN(_FLAGS), - old, buf, size, &last)) { - size += 256; - tmp = (char *) xrealloc(buf, size); - if (!tmp) - log_fatal("Can't claim memory for OS_GSTrans buffer!\n"); - buf = tmp; - } - - buf[last] = '\0'; - tmp = (char *) xrealloc(buf, last + 1); - if (!tmp) - log_fatal("Can't realloc memory after OS_GSTrans!\n"); - - return tmp; -} - -/*************** - * Extract from a given path the filename component. - * (cloned from util/fileutil.c and then heavily modified) - */ -char * -riscos_make_basename(const char *filepath, const char *realfname) -{ - char *result, *p; - int i, filetype; - - if ( (p = strrchr(filepath, DIRSEP_C)) ) - p++; - else if ( (p = strrchr(filepath, ':')) ) - p++; - else - p = (char*) filepath; - - i = strlen(p); - result = xmalloc(i + 5); - if (!result) - log_fatal("Can't claim memory for riscos_make_basename() buffer!\n"); - strcpy(result, p); - - filetype = riscos_get_filetype( realfname ); - result[i++] = ','; - result[i++] = "0123456789abcdef"[(filetype >> 8) & 0xf]; - result[i++] = "0123456789abcdef"[(filetype >> 4) & 0xf]; - result[i++] = "0123456789abcdef"[(filetype >> 0) & 0xf]; - result[i] = 0; - - for(i=0; i<strlen(result); ++i) - if(result[i] == '/') - result[i] = '.'; - - return result; -} - -#define RegEx_CompilePattern 0x52AC0 -#define RegEx_Search 0x52AC2 -#define RegEx_Free 0x52AC7 -#define RegEx_CompileExtendedPattern 0x52AC9 - -static const char * const regex_path[] = { - "GnuPG:RegEx", - "System:310.Modules.RegEx", - "System:Modules.RegEx", - NULL -}; - -int -riscos_check_regexp(const char *exp, const char *string, int debug) -{ - static int regex_initialized = 0; - int ret; - char *buf; - - if (!regex_initialized) - regex_initialized = riscos_load_module("RegEx", regex_path, 0); - - if (!regex_initialized) { - log_info("Regular expressions cannot be used!\n"); - return 0; - } - - if (_swix(RegEx_CompileExtendedPattern, _INR(0,2) | _OUT(0) | _OUT(3), - 0, exp, 1<<18, - &buf, &ret)) { - log_info("RegEx could not compile pattern \"%s\".\n", exp); - log_info("ErrorCode = %i\n", ret); - return 0; - } - - if (_swix(RegEx_Search, _INR(0,4) | _OUT(5), - buf, string, -1, 0, -1, - &ret)) { - log_info("RegEx error during execution of serach pattern \"%s\"\n", - exp); - log_info("on string \"%s\"\n", string); - return 0; - } - - _swix(RegEx_Free, _IN(0), buf); - - if(debug) - log_debug("regexp \"%s\" on \"%s\": %s\n",exp,string,ret>=0?"YES":"NO"); - - return (ret>=0); -} - -#ifdef DEBUG -void -riscos_list_openfiles(void) -{ - char *name; - int i, len; - - for (i = 255; i >= 0; --i) { - if (_swix(OS_Args, _INR(0,2) | _IN(5) | _OUT(5), 7, i, 0, 0, &len)) - continue; - - name = (char *) xmalloc(1-len); - if (!name) - log_fatal("Can't claim memory for OS_Args buffer!\n"); - - if (_swix(OS_Args, _INR(0,2) | _IN(5), 7, i, name, 1-len)) { - xfree(name); - log_fatal("Error when calling OS_Args(7)!\n"); - } - - if (_swix(OS_Args, _INR(0,1) | _OUT(0), 254, i, &len)) { - xfree(name); - log_fatal("Error when calling OS_Args(254)!\n"); - } - - printf("%3i: %s (%c%c)\n", i, name, - (len & 0x40) ? 'R' : 0, - (len & 0x80) ? 'W' : 0); - xfree(name); - } -} -#endif - -void -riscos_not_implemented(const char *feature) -{ - log_info("%s is not implemented in the RISC OS version!\n", feature); -} - -#endif /* !__RISCOS__C__ */ diff --git a/util/secmem.c b/util/secmem.c deleted file mode 100644 index 5ffbfc6d3..000000000 --- a/util/secmem.c +++ /dev/null @@ -1,499 +0,0 @@ -/* secmem.c - memory allocation from a secure heap - * Copyright (C) 1998, 1999, 2000 Free Software Foundation, Inc. - * - * This file is part of GnuPG. - * - * GnuPG is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * GnuPG is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, - * USA. - */ - -#include <config.h> -#include <stdio.h> -#include <stdlib.h> -#include <string.h> -#include <errno.h> -#include <stdarg.h> -#include <unistd.h> -#if defined(HAVE_MLOCK) || defined(HAVE_MMAP) -#include <sys/mman.h> -#include <sys/types.h> -#include <fcntl.h> -#ifdef USE_CAPABILITIES -#include <sys/capability.h> -#endif -#ifdef HAVE_PLOCK -#include <sys/lock.h> -#endif -#endif - -#include "types.h" -#include "memory.h" -#include "util.h" -#include "i18n.h" - -/* MinGW doesn't seem to prototype getpagesize, though it does have - it. */ -#if !HAVE_DECL_GETPAGESIZE -int getpagesize(void); -#endif - -#if defined(MAP_ANON) && !defined(MAP_ANONYMOUS) -#define MAP_ANONYMOUS MAP_ANON -#endif -/* It seems that Slackware 7.1 does not know about EPERM */ -#if !defined(EPERM) && defined(ENOMEM) -#define EPERM ENOMEM -#endif - - -#define DEFAULT_POOLSIZE 16384 - -typedef struct memblock_struct MEMBLOCK; -struct memblock_struct { - unsigned size; - union { - MEMBLOCK *next; - PROPERLY_ALIGNED_TYPE aligned; - } u; -}; - - - -static void *pool; -static volatile int pool_okay; /* may be checked in an atexit function */ -#ifdef HAVE_MMAP -static volatile int pool_is_mmapped; -#endif -static size_t poolsize; /* allocated length */ -static size_t poollen; /* used length */ -static MEMBLOCK *unused_blocks; -static unsigned max_alloced; -static unsigned cur_alloced; -static unsigned max_blocks; -static unsigned cur_blocks; -static int disable_secmem; -static int show_warning; -static int no_warning; -static int suspend_warning; - - -static void -print_warn(void) -{ - if (!no_warning) - { - log_info(_("WARNING: using insecure memory!\n")); - log_info(_("please see http://www.gnupg.org/faq.html" - " for more information\n")); - } -} - - -static void -lock_pool( void *p, size_t n ) -{ -#if defined(USE_CAPABILITIES) && defined(HAVE_MLOCK) - int err; - - cap_set_proc( cap_from_text("cap_ipc_lock+ep") ); - err = mlock( p, n ); - if( err && errno ) - err = errno; - cap_set_proc( cap_from_text("cap_ipc_lock+p") ); - - if( err ) { - if( errno != EPERM -#ifdef EAGAIN /* OpenBSD returns this */ - && errno != EAGAIN -#endif -#ifdef ENOSYS /* Some SCOs return this (function not implemented) */ - && errno != ENOSYS -#endif -#ifdef ENOMEM /* Linux can return this */ - && errno != ENOMEM -#endif - ) - log_error("can't lock memory: %s\n", strerror(err)); - show_warning = 1; - } - -#elif defined(HAVE_MLOCK) - uid_t uid; - int err; - - uid = getuid(); - -#ifdef HAVE_BROKEN_MLOCK - /* ick. but at least we get secured memory. about to lock - entire data segment. */ -#ifdef HAVE_PLOCK -# ifdef _AIX - /* The configure for AIX returns broken mlock but the plock has - the strange requirement to somehow set the stack limit first. - The problem might turn out in indeterministic program behaviour - and hanging processes which can somehow be solved when enough - processes are clogging up the memory. To get this problem out - of the way we simply don't try to lock the memory at all. - */ - errno = EPERM; - err = errno; -# else /* !_AIX */ - err = plock( DATLOCK ); - if( err && errno ) - err = errno; -# endif /*_AIX*/ -#else /*!HAVE_PLOCK*/ - if( uid ) { - errno = EPERM; - err = errno; - } - else { - err = mlock( p, n ); - if( err && errno ) - err = errno; - } -#endif /*!HAVE_PLOCK*/ -#else - err = mlock( p, n ); - if( err && errno ) - err = errno; -#endif - - if( uid && !geteuid() ) { - /* check that we really dropped the privs. - * Note: setuid(0) should always fail */ - if( setuid( uid ) || getuid() != geteuid() || !setuid(0) ) - log_fatal("failed to reset uid: %s\n", strerror(errno)); - } - - if( err ) { - if( errno != EPERM -#ifdef EAGAIN /* OpenBSD returns this */ - && errno != EAGAIN -#endif -#ifdef ENOSYS /* Some SCOs return this (function not implemented) */ - && errno != ENOSYS -#endif -#ifdef ENOMEM /* Linux can return this */ - && errno != ENOMEM -#endif - ) - log_error("can't lock memory: %s\n", strerror(err)); - show_warning = 1; - } - -#elif defined ( __QNX__ ) - /* QNX does not page at all, so the whole secure memory stuff does - * not make much sense. However it is still of use because it - * wipes out the memory on a free(). - * Therefore it is sufficient to suppress the warning - */ -#elif defined (HAVE_DOSISH_SYSTEM) || defined (__CYGWIN__) - /* It does not make sense to print such a warning, given the fact that - * this whole Windows !@#$% and their user base are inherently insecure - */ -#elif defined (__riscos__) - /* no virtual memory on RISC OS, so no pages are swapped to disc, - * besides we don't have mmap, so we don't use it! ;-) - * But don't complain, as explained above. - */ -#else - log_info("Please note that you don't have secure memory on this system\n"); -#endif -} - - -static void -init_pool( size_t n) -{ - size_t pgsize; - - poolsize = n; - - if( disable_secmem ) - log_bug("secure memory is disabled"); - -#ifdef HAVE_GETPAGESIZE - pgsize = getpagesize(); -#else - pgsize = 4096; -#endif - -#ifdef HAVE_MMAP - poolsize = (poolsize + pgsize -1 ) & ~(pgsize-1); -#ifdef MAP_ANONYMOUS - pool = mmap( 0, poolsize, PROT_READ|PROT_WRITE, - MAP_PRIVATE|MAP_ANONYMOUS, -1, 0); -#else /* map /dev/zero instead */ - { int fd; - - fd = open("/dev/zero", O_RDWR); - if( fd == -1 ) { - log_error("can't open /dev/zero: %s\n", strerror(errno) ); - pool = (void*)-1; - } - else { - pool = mmap( 0, poolsize, PROT_READ|PROT_WRITE, - MAP_PRIVATE, fd, 0); - close (fd); - } - } -#endif - if( pool == (void*)-1 ) - log_info("can't mmap pool of %u bytes: %s - using malloc\n", - (unsigned)poolsize, strerror(errno)); - else { - pool_is_mmapped = 1; - pool_okay = 1; - } - -#endif - if( !pool_okay ) { - pool = malloc( poolsize ); - if( !pool ) - log_fatal("can't allocate memory pool of %u bytes\n", - (unsigned)poolsize); - else - pool_okay = 1; - } - lock_pool( pool, poolsize ); - poollen = 0; -} - - -/* concatenate unused blocks */ -static void -compress_pool(void) -{ - /* fixme: we really should do this */ -} - -void -secmem_set_flags( unsigned flags ) -{ - int was_susp = suspend_warning; - - no_warning = flags & 1; - suspend_warning = flags & 2; - - /* and now issue the warning if it is not longer suspended */ - if( was_susp && !suspend_warning && show_warning ) { - show_warning = 0; - print_warn(); - } -} - -unsigned -secmem_get_flags(void) -{ - unsigned flags; - - flags = no_warning ? 1:0; - flags |= suspend_warning ? 2:0; - return flags; -} - -/* Returns 1 if memory was locked, 0 if not. */ -int -secmem_init( size_t n ) -{ - if( !n ) { -#ifndef __riscos__ -#ifdef USE_CAPABILITIES - /* drop all capabilities */ - cap_set_proc( cap_from_text("all-eip") ); - -#elif !defined(HAVE_DOSISH_SYSTEM) - uid_t uid; - - disable_secmem=1; - uid = getuid(); - if( uid != geteuid() ) { - if( setuid( uid ) || getuid() != geteuid() || !setuid(0) ) - log_fatal("failed to drop setuid\n" ); - } -#endif -#endif /* !__riscos__ */ - } - else { - if( n < DEFAULT_POOLSIZE ) - n = DEFAULT_POOLSIZE; - if( !pool_okay ) - init_pool(n); - else - log_error("Oops, secure memory pool already initialized\n"); - } - - return !show_warning; -} - - -void * -secmem_malloc( size_t size ) -{ - MEMBLOCK *mb, *mb2; - int compressed=0; - - if( !pool_okay ) { - log_info( - _("operation is not possible without initialized secure memory\n")); - log_info(_("(you may have used the wrong program for this task)\n")); - exit(2); - } - if( show_warning && !suspend_warning ) { - show_warning = 0; - print_warn(); - } - - /* Blocks are always a multiple of 32. Note that we allocate an - extra of the size of an entire MEMBLOCK. This is required - becuase we do not only need the SIZE info but also extra space - to chain up unused memory blocks. */ - size += sizeof(MEMBLOCK); - size = ((size + 31) / 32) * 32; - - retry: - /* try to get it from the used blocks */ - for(mb = unused_blocks,mb2=NULL; mb; mb2=mb, mb = mb->u.next ) - if( mb->size >= size ) { - if( mb2 ) - mb2->u.next = mb->u.next; - else - unused_blocks = mb->u.next; - goto leave; - } - /* allocate a new block */ - if( (poollen + size <= poolsize) ) { - mb = (void*)((char*)pool + poollen); - poollen += size; - mb->size = size; - } - else if( !compressed ) { - compressed=1; - compress_pool(); - goto retry; - } - else - return NULL; - - leave: - cur_alloced += mb->size; - cur_blocks++; - if( cur_alloced > max_alloced ) - max_alloced = cur_alloced; - if( cur_blocks > max_blocks ) - max_blocks = cur_blocks; - - return &mb->u.aligned.c; -} - - -void * -secmexrealloc( void *p, size_t newsize ) -{ - MEMBLOCK *mb; - size_t size; - void *a; - - mb = (MEMBLOCK*)((char*)p - ((size_t) &((MEMBLOCK*)0)->u.aligned.c)); - size = mb->size; - if (size < sizeof(MEMBLOCK)) - log_bug ("secure memory corrupted at block %p\n", (void *)mb); - size -= ((size_t) &((MEMBLOCK*)0)->u.aligned.c); - - if( newsize <= size ) - return p; /* It is easier not to shrink the memory. */ - a = secmem_malloc( newsize ); - if ( a ) { - memcpy(a, p, size); - memset((char*)a+size, 0, newsize-size); - secmem_free(p); - } - return a; -} - - -void -secmem_free( void *a ) -{ - MEMBLOCK *mb; - size_t size; - - if( !a ) - return; - - mb = (MEMBLOCK*)((char*)a - ((size_t) &((MEMBLOCK*)0)->u.aligned.c)); - size = mb->size; - /* This does not make much sense: probably this memory is held in the - * cache. We do it anyway: */ - wipememory2(mb, 0xff, size ); - wipememory2(mb, 0xaa, size ); - wipememory2(mb, 0x55, size ); - wipememory2(mb, 0x00, size ); - mb->size = size; - mb->u.next = unused_blocks; - unused_blocks = mb; - cur_blocks--; - cur_alloced -= size; -} - -int -m_is_secure( const void *p ) -{ - return p >= pool && p < (void*)((char*)pool+poolsize); -} - - - -/**************** - * Warning: This code might be called by an interrupt handler - * and frankly, there should really be such a handler, - * to make sure that the memory is wiped out. - * We hope that the OS wipes out mlocked memory after - * receiving a SIGKILL - it really should do so, otherwise - * there is no chance to get the secure memory cleaned. - */ -void -secmem_term() -{ - if( !pool_okay ) - return; - - wipememory2( pool, 0xff, poolsize); - wipememory2( pool, 0xaa, poolsize); - wipememory2( pool, 0x55, poolsize); - wipememory2( pool, 0x00, poolsize); -#ifdef HAVE_MMAP - if( pool_is_mmapped ) - munmap( pool, poolsize ); -#endif - pool = NULL; - pool_okay = 0; - poolsize=0; - poollen=0; - unused_blocks=NULL; -} - - -void -secmem_dump_stats() -{ - if( disable_secmem ) - return; - fprintf(stderr, - "secmem usage: %u/%u bytes in %u/%u blocks of pool %lu/%lu\n", - cur_alloced, max_alloced, cur_blocks, max_blocks, - (ulong)poollen, (ulong)poolsize ); -} diff --git a/util/simple-gettext.c b/util/simple-gettext.c deleted file mode 100644 index 3249775bf..000000000 --- a/util/simple-gettext.c +++ /dev/null @@ -1,467 +0,0 @@ -/* simple-gettext.c - a simplified version of gettext. - * Copyright (C) 1995, 1996, 1997, 1999, - * 2005 Free Software Foundation, Inc. - * - * This file is part of GnuPG. - * - * GnuPG is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * GnuPG is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, - * USA. - */ - -/* This is a simplified version of gettext written by Ulrich Drepper. - * It is used for the Win32 version of GnuPG beucase all the overhead - * of gettext is not needed and we have to do some special Win32 stuff. - * I decided that this is far easier than to tweak gettext for the special - * cases (I tried it but it is a lot of code). wk 15.09.99 - */ - -#include <config.h> -#ifdef USE_SIMPLE_GETTEXT -#if !defined (_WIN32) && !defined (__CYGWIN32__) -#error This file can only be used under Windows or Cygwin32 -#endif - -#include <stdio.h> -#include <stdlib.h> -#include <string.h> -#include <ctype.h> -#include <errno.h> -#include <sys/types.h> -#include <sys/stat.h> -#include "types.h" -#include "util.h" - - -/* The magic number of the GNU message catalog format. */ -#define MAGIC 0x950412de -#define MAGIC_SWAPPED 0xde120495 - -/* Revision number of the currently used .mo (binary) file format. */ -#define MO_REVISION_NUMBER 0 - - -/* Header for binary .mo file format. */ -struct mo_file_header -{ - /* The magic number. */ - u32 magic; - /* The revision number of the file format. */ - u32 revision; - /* The number of strings pairs. */ - u32 nstrings; - /* Offset of table with start offsets of original strings. */ - u32 orig_tab_offset; - /* Offset of table with start offsets of translation strings. */ - u32 trans_tab_offset; - /* Size of hashing table. */ - u32 hash_tab_size; - /* Offset of first hashing entry. */ - u32 hash_tab_offset; -}; - -struct string_desc -{ - /* Length of addressed string. */ - u32 length; - /* Offset of string in file. */ - u32 offset; -}; - - -struct overflow_space_s -{ - struct overflow_space_s *next; - u32 idx; - char d[1]; -}; - -struct loaded_domain -{ - char *data; - int must_swap; - u32 nstrings; - char *mapped; /* 0 = not yet mapped, 1 = mapped, - 2 = mapped to - overflow space */ - struct overflow_space_s *overflow_space; - struct string_desc *orig_tab; - struct string_desc *trans_tab; - u32 hash_size; - u32 *hash_tab; -}; - - -static struct loaded_domain *the_domain; - -static __inline__ u32 -do_swap_u32( u32 i ) -{ - return (i << 24) | ((i & 0xff00) << 8) | ((i >> 8) & 0xff00) | (i >> 24); -} - -#define SWAPIT(flag, data) ((flag) ? do_swap_u32(data) : (data) ) - - -/* We assume to have `unsigned long int' value with at least 32 bits. */ -#define HASHWORDBITS 32 - -/* The so called `hashpjw' function by P.J. Weinberger - [see Aho/Sethi/Ullman, COMPILERS: Principles, Techniques and Tools, - 1986, 1987 Bell Telephone Laboratories, Inc.] */ - -static __inline__ ulong -hash_string( const char *str_param ) -{ - unsigned long int hval, g; - const char *str = str_param; - - hval = 0; - while (*str != '\0') - { - hval <<= 4; - hval += (unsigned long int) *str++; - g = hval & ((unsigned long int) 0xf << (HASHWORDBITS - 4)); - if (g != 0) - { - hval ^= g >> (HASHWORDBITS - 8); - hval ^= g; - } - } - return hval; -} - - -static struct loaded_domain * -load_domain( const char *filename ) -{ - FILE *fp; - size_t size; - struct stat st; - struct mo_file_header *data = NULL; - struct loaded_domain *domain = NULL; - size_t to_read; - char *read_ptr; - - fp = fopen( filename, "rb" ); - if( !fp ) - return NULL; /* can't open the file */ - /* we must know about the size of the file */ - if( fstat( fileno(fp ), &st ) - || (size = (size_t)st.st_size) != st.st_size - || size < sizeof (struct mo_file_header) ) { - fclose( fp ); - return NULL; - } - - data = malloc( size ); - if( !data ) { - fclose( fp ); - return NULL; /* out of memory */ - } - - to_read = size; - read_ptr = (char *) data; - do { - long int nb = fread( read_ptr, 1, to_read, fp ); - if( nb < to_read ) { - fclose (fp); - free(data); - return NULL; /* read error */ - } - read_ptr += nb; - to_read -= nb; - } while( to_read > 0 ); - fclose (fp); - - /* Using the magic number we can test whether it really is a message - * catalog file. */ - if( data->magic != MAGIC && data->magic != MAGIC_SWAPPED ) { - /* The magic number is wrong: not a message catalog file. */ - free( data ); - return NULL; - } - - domain = calloc( 1, sizeof *domain ); - if( !domain ) { - free( data ); - return NULL; - } - domain->data = (char *) data; - domain->must_swap = data->magic != MAGIC; - - /* Fill in the information about the available tables. */ - switch( SWAPIT(domain->must_swap, data->revision) ) { - case 0: - domain->nstrings = SWAPIT(domain->must_swap, data->nstrings); - domain->orig_tab = (struct string_desc *) - ((char *) data + SWAPIT(domain->must_swap, data->orig_tab_offset)); - domain->trans_tab = (struct string_desc *) - ((char *) data + SWAPIT(domain->must_swap, data->trans_tab_offset)); - domain->hash_size = SWAPIT(domain->must_swap, data->hash_tab_size); - domain->hash_tab = (u32 *) - ((char *) data + SWAPIT(domain->must_swap, data->hash_tab_offset)); - break; - - default: /* This is an invalid revision. */ - free( data ); - free( domain ); - return NULL; - } - - /* Allocate an array to keep track of code page mappings. */ - domain->mapped = calloc( 1, domain->nstrings ); - if( !domain->mapped ) { - free( data ); - free( domain ); - return NULL; - } - - return domain; -} - - -/**************** - * Set the file used for translations. Pass a NULL to disable - * translation. A new filename may be set at anytime. If REGKEY is - * not NULL, the function tries to selected the language the registry - * key "Lang" below that key. WARNING: After changing the filename you - * should not access any data retrieved by gettext(). - */ -int -set_gettext_file ( const char *filename, const char *regkey ) -{ - struct loaded_domain *domain = NULL; - - if( filename && *filename ) { - if( filename[0] == '/' -#ifdef HAVE_DRIVE_LETTERS - || ( isalpha(filename[0]) - && filename[1] == ':' - && (filename[2] == '/' || filename[2] == '\\') ) -#endif - ) { - /* absolute path - use it as is */ - domain = load_domain( filename ); - } - else if (regkey) { /* Standard. */ - char *instdir, *langid, *fname; - char *p; - - instdir = read_w32_registry_string ("HKEY_LOCAL_MACHINE", - regkey, - "Install Directory"); - if (!instdir) - return -1; - langid = read_w32_registry_string (NULL, /* HKCU then HKLM */ - regkey, - "Lang"); - if (!langid) { - free (instdir); - return -1; - } - /* Strip stuff after a dot in case the user tried to enter - * the entire locale synatcs as usual for POSIX. */ - p = strchr (langid, '.'); - if (p) - *p = 0; - - /* Build the key: "<instdir>/<domain>.nls/<langid>.mo" We - use a directory below the installation directory with - the domain included in case the software has been - insalled with other software altogether at the same - place. */ - fname = malloc (strlen (instdir) + 1 + strlen (filename) + 5 - + strlen (langid) + 3 + 1); - if (!fname) { - free (instdir); - free (langid); - return -1; - } - strcpy (stpcpy (stpcpy (stpcpy (stpcpy ( stpcpy (fname, - instdir),"\\"), filename), ".nls\\"), langid), ".mo"); - free (instdir); - free (langid); - - /* Better make sure that we don't mix forward and - backward slashes. It seems that some Windoze - versions don't accept this. */ - for (p=fname; *p; p++) { - if (*p == '/') - *p = '\\'; - } - domain = load_domain (fname); - free(fname); - } - - if (!domain) - return -1; - } - - if( the_domain ) { - struct overflow_space_s *os, *os2; - free( the_domain->data ); - free( the_domain->mapped ); - for (os=the_domain->overflow_space; os; os = os2) { - os2 = os->next; - free (os); - } - free( the_domain ); - the_domain = NULL; - } - the_domain = domain; - return 0; -} - - -static const char* -get_string( struct loaded_domain *domain, u32 idx ) -{ - struct overflow_space_s *os; - char *p; - - p = domain->data + SWAPIT(domain->must_swap, domain->trans_tab[idx].offset); - if (!domain->mapped[idx]) - { - size_t plen, buflen; - char *buf; - - domain->mapped[idx] = 1; - - plen = strlen (p); - buf = utf8_to_native (p, plen, -1); - buflen = strlen (buf); - if (buflen <= plen) - strcpy (p, buf); - else - { - /* There is not enough space for the translation - store it - in the overflow_space else and mark that in the mapped - array. Because we expect that this won't happen too - often, we use a simple linked list. */ - os = malloc (sizeof *os + buflen); - if (os) - { - os->idx = idx; - strcpy (os->d, buf); - os->next = domain->overflow_space; - domain->overflow_space = os; - p = os->d; - } - else - p = "ERROR in GETTEXT MALLOC"; - } - xfree (buf); - } - else if (domain->mapped[idx] == 2) - { /* We need to get the string from the overflow_space. */ - for (os=domain->overflow_space; os; os = os->next) - if (os->idx == idx) - return (const char*)os->d; - p = "ERROR in GETTEXT\n"; - } - return (const char*)p; -} - - - -const char * -gettext( const char *msgid ) -{ - struct loaded_domain *domain; - size_t act = 0; - size_t top, bottom; - - if( !(domain = the_domain) ) - goto not_found; - - /* Locate the MSGID and its translation. */ - if( domain->hash_size > 2 && domain->hash_tab ) { - /* Use the hashing table. */ - u32 len = strlen (msgid); - u32 hash_val = hash_string (msgid); - u32 idx = hash_val % domain->hash_size; - u32 incr = 1 + (hash_val % (domain->hash_size - 2)); - u32 nstr = SWAPIT (domain->must_swap, domain->hash_tab[idx]); - - if ( !nstr ) /* Hash table entry is empty. */ - goto not_found; - - if( SWAPIT(domain->must_swap, - domain->orig_tab[nstr - 1].length) == len - && !strcmp( msgid, - domain->data + SWAPIT(domain->must_swap, - domain->orig_tab[nstr - 1].offset)) ) - return get_string( domain, nstr - 1 ); - - for(;;) { - if (idx >= domain->hash_size - incr) - idx -= domain->hash_size - incr; - else - idx += incr; - - nstr = SWAPIT(domain->must_swap, domain->hash_tab[idx]); - if( !nstr ) - goto not_found; /* Hash table entry is empty. */ - - if ( SWAPIT(domain->must_swap, - domain->orig_tab[nstr - 1].length) == len - && !strcmp (msgid, - domain->data + SWAPIT(domain->must_swap, - domain->orig_tab[nstr - 1].offset))) - return get_string( domain, nstr-1 ); - } - /* NOTREACHED */ - } - - /* Now we try the default method: binary search in the sorted - array of messages. */ - bottom = 0; - top = domain->nstrings; - while( bottom < top ) { - int cmp_val; - - act = (bottom + top) / 2; - cmp_val = strcmp(msgid, domain->data - + SWAPIT(domain->must_swap, - domain->orig_tab[act].offset)); - if (cmp_val < 0) - top = act; - else if (cmp_val > 0) - bottom = act + 1; - else - return get_string( domain, act ); - } - - not_found: - return msgid; -} - -#if 0 - unsigned int cp1, cp2; - - cp1 = GetConsoleCP(); - cp2 = GetConsoleOutputCP(); - - log_info("InputCP=%u OutputCP=%u\n", cp1, cp2 ); - - if( !SetConsoleOutputCP( 1252 ) ) - log_info("SetConsoleOutputCP failed: %s\n", w32_strerror (0)); - - cp1 = GetConsoleCP(); - cp2 = GetConsoleOutputCP(); - log_info("InputCP=%u OutputCP=%u after switch1\n", cp1, cp2 ); -#endif - -#endif /* USE_SIMPLE_GETTEXT */ diff --git a/util/srv.c b/util/srv.c deleted file mode 100644 index 95187dbc8..000000000 --- a/util/srv.c +++ /dev/null @@ -1,257 +0,0 @@ -/* srv.c - DNS SRV code - * Copyright (C) 2003 Free Software Foundation, Inc. - * - * This file is part of GNUPG. - * - * GNUPG is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * GNUPG is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, - * USA. - */ - -#include <config.h> -#include <sys/types.h> -#ifdef _WIN32 -#include <windows.h> -#else -#include <netinet/in.h> -#include <arpa/nameser.h> -#include <resolv.h> -#endif -#include <unistd.h> -#include <stdlib.h> -#include <string.h> -#include <time.h> -#include "memory.h" -#include "types.h" -#include "srv.h" - -/* Not every installation has gotten around to supporting SRVs - yet... */ -#ifndef T_SRV -#define T_SRV 33 -#endif - -static int -priosort(const void *a,const void *b) -{ - const struct srventry *sa=a,*sb=b; - if(sa->priority>sb->priority) - return 1; - else if(sa->priority<sb->priority) - return -1; - else - return 0; -} - -int -getsrv(const char *name,struct srventry **list) -{ - unsigned char answer[PACKETSZ]; - int r,srvcount=0; - unsigned char *pt,*emsg; - u16 count,dlen; - - *list=NULL; - - r=res_query(name,C_IN,T_SRV,answer,PACKETSZ); - if(r<sizeof(HEADER) || r>PACKETSZ) - return -1; - - if((((HEADER *)answer)->rcode)==NOERROR && - (count=ntohs(((HEADER *)answer)->ancount))) - { - int i,rc; - - emsg=&answer[r]; - pt=&answer[sizeof(HEADER)]; - - /* Skip over the query */ - - rc=dn_skipname(pt,emsg); - if(rc==-1) - goto fail; - - pt+=rc+QFIXEDSZ; - - while(count-->0 && pt<emsg) - { - struct srventry *srv=NULL; - u16 type,class; - - *list=xrealloc(*list,(srvcount+1)*sizeof(struct srventry)); - memset(&(*list)[srvcount],0,sizeof(struct srventry)); - srv=&(*list)[srvcount]; - srvcount++; - - rc=dn_skipname(pt,emsg); /* the name we just queried for */ - if(rc==-1) - goto fail; - pt+=rc; - - /* Truncated message? */ - if((emsg-pt)<16) - goto fail; - - type=*pt++ << 8; - type|=*pt++; - /* We asked for SRV and got something else !? */ - if(type!=T_SRV) - goto fail; - - class=*pt++ << 8; - class|=*pt++; - /* We asked for IN and got something else !? */ - if(class!=C_IN) - goto fail; - - pt+=4; /* ttl */ - dlen=*pt++ << 8; - dlen|=*pt++; - srv->priority=*pt++ << 8; - srv->priority|=*pt++; - srv->weight=*pt++ << 8; - srv->weight|=*pt++; - srv->port=*pt++ << 8; - srv->port|=*pt++; - - /* Get the name. 2782 doesn't allow name compression, but - dn_expand still works to pull the name out of the - packet. */ - rc=dn_expand(answer,emsg,pt,srv->target,MAXDNAME); - if(rc==1 && srv->target[0]==0) /* "." */ - goto noanswer; - if(rc==-1) - goto fail; - pt+=rc; - /* Corrupt packet? */ - if(dlen!=rc+6) - goto fail; - -#if 0 - printf("count=%d\n",srvcount); - printf("priority=%d\n",srv->priority); - printf("weight=%d\n",srv->weight); - printf("port=%d\n",srv->port); - printf("target=%s\n",srv->target); -#endif - } - - /* Now we have an array of all the srv records. */ - - /* Order by priority */ - qsort(*list,srvcount,sizeof(struct srventry),priosort); - - /* For each priority, move the zero-weighted items first. */ - for(i=0;i<srvcount;i++) - { - int j; - - for(j=i;j<srvcount && (*list)[i].priority==(*list)[j].priority;j++) - { - if((*list)[j].weight==0) - { - /* Swap j with i */ - if(j!=i) - { - struct srventry temp; - - memcpy(&temp,&(*list)[j],sizeof(struct srventry)); - memcpy(&(*list)[j],&(*list)[i],sizeof(struct srventry)); - memcpy(&(*list)[i],&temp,sizeof(struct srventry)); - } - - break; - } - } - } - - /* Run the RFC-2782 weighting algorithm. We don't need very - high quality randomness for this, so regular libc srand/rand - is sufficient. */ - srand(time(NULL)*getpid()); - - for(i=0;i<srvcount;i++) - { - int j; - float prio_count=0,chose; - - for(j=i;j<srvcount && (*list)[i].priority==(*list)[j].priority;j++) - { - prio_count+=(*list)[j].weight; - (*list)[j].run_count=prio_count; - } - - chose=prio_count*rand()/RAND_MAX; - - for(j=i;j<srvcount && (*list)[i].priority==(*list)[j].priority;j++) - { - if(chose<=(*list)[j].run_count) - { - /* Swap j with i */ - if(j!=i) - { - struct srventry temp; - - memcpy(&temp,&(*list)[j],sizeof(struct srventry)); - memcpy(&(*list)[j],&(*list)[i],sizeof(struct srventry)); - memcpy(&(*list)[i],&temp,sizeof(struct srventry)); - } - break; - } - } - } - } - - return srvcount; - - noanswer: - xfree(*list); - *list=NULL; - return 0; - - fail: - xfree(*list); - *list=NULL; - return -1; -} - -#ifdef TEST -int -main(int argc,char *argv[]) -{ - struct srventry *srv; - int rc,i; - - rc=getsrv("_hkp._tcp.wwwkeys.pgp.net",&srv); - printf("Count=%d\n\n",rc); - for(i=0;i<rc;i++) - { - printf("priority=%d\n",srv[i].priority); - printf("weight=%d\n",srv[i].weight); - printf("port=%d\n",srv[i].port); - printf("target=%s\n",srv[i].target); - printf("\n"); - } - - xfree(srv); - - return 0; -} -#endif /* TEST */ - -/* -Local Variables: -compile-command: "cc -DTEST -I.. -I../include -Wall -g -o srv srv.c -lresolv libutil.a" -End: -*/ diff --git a/util/srv.h b/util/srv.h deleted file mode 100644 index a81ebd573..000000000 --- a/util/srv.h +++ /dev/null @@ -1,51 +0,0 @@ -/* srv.h - * Copyright (C) 2003, 2004 Free Software Foundation, Inc. - * - * This file is part of GNUPG. - * - * GNUPG is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * GNUPG is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, - * USA. - */ - -#ifndef _SRV_H_ -#define _SRV_H_ - -#ifdef USE_DNS_SRV -#ifdef _WIN32 -#include <windows.h> -#else -#include <netinet/in.h> -#include <arpa/nameser.h> -#include <resolv.h> -#endif /* !_WIN32 */ -#endif /* USE_DNS_SRV */ -#include "types.h" - -#ifndef MAXDNAME -#define MAXDNAME 1025 -#endif - -struct srventry -{ - u16 priority; - u16 weight; - u16 port; - int run_count; - char target[MAXDNAME]; -}; - -int getsrv(const char *name,struct srventry **list); - -#endif /* !_SRV_H_ */ diff --git a/util/strgutil.c b/util/strgutil.c deleted file mode 100644 index cffdfcf77..000000000 --- a/util/strgutil.c +++ /dev/null @@ -1,1373 +0,0 @@ -/* strgutil.c - string utilities - * Copyright (C) 1994, 1998, 1999, 2000, 2001, - * 2003, 2004, 2005 Free Software Foundation, Inc. - * - * This file is part of GnuPG. - * - * GnuPG is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * GnuPG is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, - * USA. - */ - -#include <config.h> -#include <stdlib.h> -#include <string.h> -#include <ctype.h> -#include <errno.h> -#ifdef HAVE_LANGINFO_CODESET -#include <langinfo.h> -#endif - -/* For W32 we use dynamic loading of the iconv dll and don't need any - * iconv headers at all. */ -#ifndef _WIN32 -# ifndef HAVE_ICONV -# undef USE_GNUPG_ICONV -# endif -#endif - -#ifdef USE_GNUPG_ICONV -# include <limits.h> -# ifndef _WIN32 -# include <iconv.h> -# endif -#endif - -#include "types.h" -#include "util.h" -#include "memory.h" -#include "i18n.h" -#include "dynload.h" - - -#ifndef USE_GNUPG_ICONV -static ushort koi8_unicode[128] = { - 0x2500,0x2502,0x250c,0x2510,0x2514,0x2518,0x251c,0x2524, - 0x252c,0x2534,0x253c,0x2580,0x2584,0x2588,0x258c,0x2590, - 0x2591,0x2592,0x2593,0x2320,0x25a0,0x2219,0x221a,0x2248, - 0x2264,0x2265,0x00a0,0x2321,0x00b0,0x00b2,0x00b7,0x00f7, - 0x2550,0x2551,0x2552,0x0451,0x2553,0x2554,0x2555,0x2556, - 0x2557,0x2558,0x2559,0x255a,0x255b,0x255c,0x255d,0x255e, - 0x255f,0x2560,0x2561,0x0401,0x2562,0x2563,0x2564,0x2565, - 0x2566,0x2567,0x2568,0x2569,0x256a,0x256b,0x256c,0x00a9, - 0x044e,0x0430,0x0431,0x0446,0x0434,0x0435,0x0444,0x0433, - 0x0445,0x0438,0x0439,0x043a,0x043b,0x043c,0x043d,0x043e, - 0x043f,0x044f,0x0440,0x0441,0x0442,0x0443,0x0436,0x0432, - 0x044c,0x044b,0x0437,0x0448,0x044d,0x0449,0x0447,0x044a, - 0x042e,0x0410,0x0411,0x0426,0x0414,0x0415,0x0424,0x0413, - 0x0425,0x0418,0x0419,0x041a,0x041b,0x041c,0x041d,0x041e, - 0x041f,0x042f,0x0420,0x0421,0x0422,0x0423,0x0416,0x0412, - 0x042c,0x042b,0x0417,0x0428,0x042d,0x0429,0x0427,0x042a -}; - -static ushort latin2_unicode[128] = { - 0x0080,0x0081,0x0082,0x0083,0x0084,0x0085,0x0086,0x0087, - 0x0088,0x0089,0x008A,0x008B,0x008C,0x008D,0x008E,0x008F, - 0x0090,0x0091,0x0092,0x0093,0x0094,0x0095,0x0096,0x0097, - 0x0098,0x0099,0x009A,0x009B,0x009C,0x009D,0x009E,0x009F, - 0x00A0,0x0104,0x02D8,0x0141,0x00A4,0x013D,0x015A,0x00A7, - 0x00A8,0x0160,0x015E,0x0164,0x0179,0x00AD,0x017D,0x017B, - 0x00B0,0x0105,0x02DB,0x0142,0x00B4,0x013E,0x015B,0x02C7, - 0x00B8,0x0161,0x015F,0x0165,0x017A,0x02DD,0x017E,0x017C, - 0x0154,0x00C1,0x00C2,0x0102,0x00C4,0x0139,0x0106,0x00C7, - 0x010C,0x00C9,0x0118,0x00CB,0x011A,0x00CD,0x00CE,0x010E, - 0x0110,0x0143,0x0147,0x00D3,0x00D4,0x0150,0x00D6,0x00D7, - 0x0158,0x016E,0x00DA,0x0170,0x00DC,0x00DD,0x0162,0x00DF, - 0x0155,0x00E1,0x00E2,0x0103,0x00E4,0x013A,0x0107,0x00E7, - 0x010D,0x00E9,0x0119,0x00EB,0x011B,0x00ED,0x00EE,0x010F, - 0x0111,0x0144,0x0148,0x00F3,0x00F4,0x0151,0x00F6,0x00F7, - 0x0159,0x016F,0x00FA,0x0171,0x00FC,0x00FD,0x0163,0x02D9 -}; -#endif /*!USE_GNUPG_ICONV*/ - - -#ifndef MB_LEN_MAX -#define MB_LEN_MAX 16 -#endif - - -static const char *active_charset_name = "iso-8859-1"; -static ushort *active_charset = NULL; -static int no_translation = 0; -static int use_iconv = 0; - - -#ifdef _WIN32 -typedef void* iconv_t; -#ifndef ICONV_CONST -#define ICONV_CONST const -#endif - -iconv_t (* __stdcall iconv_open) (const char *tocode, const char *fromcode); -size_t (* __stdcall iconv) (iconv_t cd, - const char **inbuf, size_t *inbytesleft, - char **outbuf, size_t *outbytesleft); -int (* __stdcall iconv_close) (iconv_t cd); - -#endif /*_WIN32*/ - - - -#ifdef _WIN32 -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 http://www.gnupg.org/download/iconv.html " - "for more information\n")); - iconv_open = NULL; - iconv = NULL; - iconv_close = NULL; - if (handle) - dlclose (handle); - } - } - return iconv_open? 0: -1; -} -#endif /* _WIN32 */ - - - - -void -free_strlist( STRLIST sl ) -{ - STRLIST sl2; - - for(; sl; sl = sl2 ) { - sl2 = sl->next; - xfree(sl); - } -} - - -STRLIST -add_to_strlist( STRLIST *list, const char *string ) -{ - STRLIST sl; - - sl = xmalloc( sizeof *sl + strlen(string)); - 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 UTF8 is done - */ -STRLIST -add_to_strlist2( STRLIST *list, const char *string, int is_utf8 ) -{ - STRLIST sl; - - if( is_utf8 ) - sl = add_to_strlist( list, string ); - else { - char *p = native_to_utf8( string ); - sl = add_to_strlist( list, p ); - xfree( p ); - } - return sl; -} - -STRLIST -append_to_strlist( STRLIST *list, const char *string ) -{ - STRLIST r, sl; - - sl = 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; -} - -STRLIST -append_to_strlist2( STRLIST *list, const char *string, int is_utf8 ) -{ - STRLIST sl; - - if( is_utf8 ) - sl = append_to_strlist( list, string ); - else { - char *p = native_to_utf8( string ); - sl = append_to_strlist( list, p ); - xfree( p ); - } - return sl; -} - - -STRLIST -strlist_prev( STRLIST head, STRLIST node ) -{ - STRLIST n; - - for(n=NULL; head && head != node; head = head->next ) - n = head; - return n; -} - -STRLIST -strlist_last( STRLIST node ) -{ - if( node ) - for( ; node->next ; node = node->next ) - ; - return node; -} - -char * -pop_strlist( STRLIST *list ) -{ - char *str=NULL; - STRLIST sl=*list; - - if(sl) - { - str=xmalloc(strlen(sl->d)+1); - strcpy(str,sl->d); - - *list=sl->next; - xfree(sl); - } - - return str; -} - -/**************** - * Look for the substring SUB in buffer and return a pointer to that - * substring in BUF or NULL if not found. - * Comparison is case-insensitive. - */ -const char * -memistr( const char *buf, size_t buflen, const char *sub ) -{ - const byte *t, *s ; - size_t n; - - for( t=buf, n=buflen, s=sub ; 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 buf; - t = buf; n = buflen; s = sub ; - } - - return NULL ; -} - -const char * -ascii_memistr( const char *buf, size_t buflen, const char *sub ) -{ - const byte *t, *s ; - size_t n; - - for( t=buf, n=buflen, s=sub ; 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 buf; - t = buf; n = buflen; s = sub ; - } - - return NULL ; -} - - -/* Like strncpy() but copy at max N-1 bytes and append a '\0'. With - * N given as 0 nothing is copied at all. With DEST given as NULL - * sufficient memory is allocated using xmalloc (note that xmalloc is - * guaranteed to succeed or to abort the process). */ -char * -mem2str( char *dest , const void *src , size_t n ) -{ - char *d; - const char *s; - - if( n ) { - if( !dest ) - dest = 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 ; -} - - - -unsigned int -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" ); -} - - -unsigned int -check_trailing_chars( const byte *line, unsigned int len, - const char *trimchars ) -{ - const byte *p, *mark; - unsigned int 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; -} - - -/**************** - * Remove trailing white spaces and return the length of the buffer - */ -unsigned int -check_trailing_ws( const byte *line, unsigned int len ) -{ - return check_trailing_chars( line, len, " \t\r\n" ); -} - - - -int -string_count_chr( const char *string, int c ) -{ - int count; - for(count=0; *string; string++ ) - if( *string == c ) - count++; - return count; -} - -#ifdef USE_GNUPG_ICONV -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; - active_charset = NULL; - use_iconv = 0; - } -} -#endif /*USE_GNUPG_ICONV*/ - -int -set_native_charset( const char *newset ) -{ - const char *full_newset; - - if (!newset) { -#ifdef _WIN32 - 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. */ - cpno = GetConsoleOutputCP (); - if (!cpno) - 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 -#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 - } - - 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; - active_charset = NULL; - use_iconv = 0; - } - else if( !ascii_strcasecmp (newset, "utf8" ) - || !ascii_strcasecmp(newset, "utf-8") ) { - active_charset_name = "utf-8"; - no_translation = 1; - active_charset = NULL; - use_iconv = 0; - } -#ifdef USE_GNUPG_ICONV - else { - iconv_t cd; - -#ifdef _WIN32 - if (load_libiconv ()) - return G10ERR_GENERAL; -#endif /*_WIN32*/ - - cd = iconv_open (full_newset, "utf-8"); - if (cd == (iconv_t)-1) { - handle_iconv_error (full_newset, "utf-8", 0); - return G10ERR_GENERAL; - } - iconv_close (cd); - cd = iconv_open ("utf-8", full_newset); - if (cd == (iconv_t)-1) { - handle_iconv_error ("utf-8", full_newset, 0); - return G10ERR_GENERAL; - } - iconv_close (cd); - active_charset_name = full_newset; - no_translation = 0; - active_charset = NULL; - use_iconv = 1; - } -#else /*!USE_GNUPG_ICONV*/ - else if( !ascii_strcasecmp( newset, "8859-2" ) ) { - active_charset_name = "iso-8859-2"; - no_translation = 0; - active_charset = latin2_unicode; - use_iconv = 0; - } - else if( !ascii_strcasecmp( newset, "koi8-r" ) ) { - active_charset_name = "koi8-r"; - no_translation = 0; - active_charset = koi8_unicode; - use_iconv = 0; - } - else - return G10ERR_GENERAL; -#endif /*!USE_GNUPG_ICONV*/ - return 0; -} - -const char* -get_native_charset() -{ - return active_charset_name; -} - -/**************** - * Convert string, which is in native encoding to UTF8 and return the - * new allocated UTF8 string. - */ -char * -native_to_utf8( const char *string ) -{ - const byte *s; - char *buffer; - byte *p; - size_t length=0; - - if (no_translation) - { /* Already utf-8 encoded. */ - buffer = xstrdup (string); - } - else if( !active_charset && !use_iconv) /* Shortcut implementation - for Latin-1. */ - { - for(s=string; *s; s++ ) - { - length++; - if( *s & 0x80 ) - length++; - } - buffer = xmalloc( length + 1 ); - for(p=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 a translation table. */ - { -#ifdef USE_GNUPG_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 = 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); - -#else /*!USE_GNUPG_ICONV*/ - for(s=string; *s; s++ ) - { - length++; - if( *s & 0x80 ) - length += 2; /* We may need up to 3 bytes. */ - } - buffer = xmalloc( length + 1 ); - for(p=buffer, s=string; *s; s++ ) { - if( *s & 0x80 ) { - ushort val = active_charset[ *s & 0x7f ]; - if( val < 0x0800 ) { - *p++ = 0xc0 | ( (val >> 6) & 0x1f ); - *p++ = 0x80 | ( val & 0x3f ); - } - else { - *p++ = 0xe0 | ( (val >> 12) & 0x0f ); - *p++ = 0x80 | ( (val >> 6) & 0x3f ); - *p++ = 0x80 | ( val & 0x3f ); - } - } - else - *p++ = *s; - } - *p = 0; -#endif /*!USE_GNUPG_ICONV*/ - - } - return buffer; -} - - -/**************** - * Convert string, which is in UTF8 to native encoding. 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. - */ -char * -utf8_to_native( const char *string, size_t length, int delim ) -{ - int nleft; - int i; - byte encbuf[8]; - int encidx; - const byte *s; - size_t n; - byte *buffer = NULL, *p = NULL; - unsigned long val = 0; - size_t slen; - int resync = 0; - - /* 1. pass (p==NULL): count the extended utf-8 characters */ - /* 2. pass (p!=NULL): create string */ - for( ;; ) { - for( slen=length, nleft=encidx=0, n=0, s=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 */ - 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; - } -#ifdef USE_GNUPG_ICONV - else if(use_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 mee 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; - } -#endif /*USE_GNUPG_ICONV*/ - else if( active_charset ) { /* table lookup */ - for(i=0; i < 128; i++ ) { - if( active_charset[i] == val ) - break; - } - if( i < 128 ) { /* we can print this one */ - if( p ) *p++ = i+128; - n++; - } - 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; - } - } - else { /* native set */ - if( val >= 0x80 && val < 256 ) { - n++; /* we can simply print this character */ - 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 = xmalloc( n + 1 ); - } -#ifdef USE_GNUPG_ICONV - else if(use_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); - xfree (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 = 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. Temporary disable the use of - * iconv and fall back to our old code. */ - xfree (buffer); - buffer = NULL; - xfree (outbuf); - use_iconv = 0; - outbuf = utf8_to_native (string, length, delim); - use_iconv = 1; - } - 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. */ - xfree (buffer); - } - iconv_close (cd); - return outbuf; - } -#endif /*USE_GNUPG_ICONV*/ - else { - *p = 0; /* make a string */ - return buffer; - } - } -} - -/**************************************************** - ******** 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) -{ - const unsigned char *p1 = (const unsigned char *)a; - const unsigned char *p2 = (const unsigned char *)b; - unsigned char c1, c2; - - if (p1 == p2) - return 0; - - do - { - c1 = ascii_tolower (*p1); - c2 = ascii_tolower (*p2); - - if (c1 == '\0') - break; - - ++p1; - ++p2; - } - while (c1 == c2); - - return c1 - c2; -} - -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 char *a, const char *b, size_t n ) -{ - 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; -} - - - -/********************************************* - ********** 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(*(unsigned char *)p); - return s; -} -#endif - -#ifndef HAVE_STRCASECMP -int -strcasecmp( const char *a, const char *b ) -{ - for( ; *a && *b; a++, b++ ) { - if( *a != *b - && toupper(*(const byte *)a) != toupper(*(const byte *)b) ) - break; - } - return *(const byte*)a - *(const byte*)b; -} -#endif - -#ifndef HAVE_STRNCASECMP -int -strncasecmp( const char *a, const char *b, size_t n ) -{ - for( ; n && *a && *b; a++, b++, n--) { - if( *a != *b - && toupper(*(const byte *)a) != toupper(*(const byte *)b) ) - break; - } - if (!n) - return 0; - return *(const byte*)a - *(const byte*)b; -} -#endif - - -#ifdef _WIN32 -/* - * Like vsprintf but provides a pointer to malloc'd storage, which - * must be freed by the caller (xfree). Taken from libiberty as - * found in gcc-2.95.2 and a little bit modernized. - * FIXME: Write a new CRT for W32. - */ -int -vasprintf (char **result, const char *format, va_list args) -{ - const char *p = format; - /* Add one to make sure that it is never zero, which might cause malloc - to return NULL. */ - int total_width = strlen (format) + 1; - va_list ap; - - /* this is not really portable but works under Windows */ - memcpy ( &ap, &args, sizeof (va_list)); - - while (*p != '\0') - { - if (*p++ == '%') - { - while (strchr ("-+ #0", *p)) - ++p; - if (*p == '*') - { - ++p; - total_width += abs (va_arg (ap, int)); - } - else - { - char *endp; - total_width += strtoul (p, &endp, 10); - p = endp; - } - if (*p == '.') - { - ++p; - if (*p == '*') - { - ++p; - total_width += abs (va_arg (ap, int)); - } - else - { - char *endp; - total_width += strtoul (p, &endp, 10); - p = endp; - } - } - while (strchr ("hlL", *p)) - ++p; - /* Should be big enough for any format specifier except %s - and floats. */ - total_width += 30; - switch (*p) - { - case 'd': - case 'i': - case 'o': - case 'u': - case 'x': - case 'X': - case 'c': - (void) va_arg (ap, int); - break; - case 'f': - case 'e': - case 'E': - case 'g': - case 'G': - (void) va_arg (ap, double); - /* Since an ieee double can have an exponent of 307, we'll - make the buffer wide enough to cover the gross case. */ - total_width += 307; - - case 's': - total_width += strlen (va_arg (ap, char *)); - break; - case 'p': - case 'n': - (void) va_arg (ap, char *); - break; - } - } - } - *result = xmalloc (total_width); - if (*result != NULL) - return vsprintf (*result, format, args); - else - return 0; -} - -int -asprintf (char **buf, const char *fmt, ...) -{ - int status; - va_list ap; - - va_start (ap, fmt); - status = vasprintf (buf, fmt, ap); - va_end (ap); - return status; -} - -const char * -w32_strerror (int w32_errno) -{ - static char strerr[256]; - int ec = (int)GetLastError (); - - if (w32_errno == 0) - w32_errno = ec; - FormatMessage (FORMAT_MESSAGE_FROM_SYSTEM, NULL, w32_errno, - MAKELANGID (LANG_NEUTRAL, SUBLANG_DEFAULT), - strerr, DIM (strerr)-1, NULL); - return strerr; -} -#endif /*_WIN32*/ - - - diff --git a/util/timegm.c b/util/timegm.c deleted file mode 100644 index 3b7931e7c..000000000 --- a/util/timegm.c +++ /dev/null @@ -1,68 +0,0 @@ -/* timegm.c - libc replacement function - * Copyright (C) 2004 Free Software Foundation, Inc. - * - * This file is part of GnuPG. - * - * GnuPG is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * GnuPG is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, - * USA. - */ - -/* - 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. - - Some BSDs don't handle the putenv("foo") case properly, so we use - unsetenv if the platform has it to remove environment variables. -*/ - -#include <config.h> -#include <time.h> -#include <stdlib.h> -#include <string.h> - -time_t -timegm(struct tm *tm) -{ - time_t answer; - char *zone; - - zone=getenv("TZ"); - putenv("TZ=UTC"); - tzset(); - answer=mktime(tm); - if(zone) - { - char *old_zone; - - old_zone=malloc(3+strlen(zone)+1); - if(old_zone) - { - strcpy(old_zone,"TZ="); - strcat(old_zone,zone); - putenv(old_zone); - } - } - else -#ifdef HAVE_UNSETENV - unsetenv("TZ"); -#else - putenv("TZ"); -#endif - - tzset(); - return answer; -} diff --git a/util/ttyio.c b/util/ttyio.c deleted file mode 100644 index 97b160ef2..000000000 --- a/util/ttyio.c +++ /dev/null @@ -1,629 +0,0 @@ -/* ttyio.c - tty i/O functions - * Copyright (C) 1998, 1999, 2000, 2001, 2002, - * 2004 Free Software Foundation, Inc. - * - * This file is part of GnuPG. - * - * GnuPG is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * GnuPG is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, - * USA. - */ - -#include <config.h> -#include <stdio.h> -#include <stdlib.h> -#include <string.h> -#include <stdarg.h> -#include <unistd.h> -#ifdef HAVE_TCGETATTR -#include <termios.h> -#else -#ifdef HAVE_TERMIO_H -/* simulate termios with termio */ -#include <termio.h> -#define termios termio -#define tcsetattr ioctl -#define TCSAFLUSH TCSETAF -#define tcgetattr(A,B) ioctl(A,TCGETA,B) -#define HAVE_TCGETATTR -#endif -#endif -#ifdef _WIN32 /* use the odd Win32 functions */ -#include <windows.h> -#ifdef HAVE_TCGETATTR -#error windows and termios -#endif -#endif -#include <errno.h> -#include <ctype.h> -#ifdef HAVE_LIBREADLINE -#include <readline/readline.h> -#include <readline/history.h> -#endif - -#include "util.h" -#include "memory.h" -#include "ttyio.h" - -#define CONTROL_D ('D' - 'A' + 1) - -#ifdef _WIN32 /* use the odd Win32 functions */ -static struct { - HANDLE in, out; -} con; -#define DEF_INPMODE (ENABLE_LINE_INPUT|ENABLE_ECHO_INPUT \ - |ENABLE_PROCESSED_INPUT ) -#define HID_INPMODE (ENABLE_LINE_INPUT|ENABLE_PROCESSED_INPUT ) -#define DEF_OUTMODE (ENABLE_WRAP_AT_EOL_OUTPUT|ENABLE_PROCESSED_OUTPUT) - -#else /* yeah, we have a real OS */ -static FILE *ttyfp = NULL; -#endif - -static int initialized; -static int last_prompt_len; -static int batchmode; -static int no_terminal; - -#ifdef HAVE_TCGETATTR - static struct termios termsave; - static int restore_termios; -#endif - - - -/* This is a wrapper around ttyname so that we can use it even when - the standard streams are redirected. It figures the name out the - first time and returns it in a statically allocated buffer. */ -const char * -tty_get_ttyname (void) -{ - static char *name; - - /* On a GNU system ctermid() always return /dev/tty, so this does - not make much sense - however if it is ever changed we do the - Right Thing now. */ -#ifdef HAVE_CTERMID - static int got_name; - - if (!got_name) - { - const char *s; - s = ctermid (NULL); - if (s) - name = strdup (s); - got_name = 1; - } -#endif - /* Assume the standard tty on memory error or when there is no - ctermid. */ - return name? name : "/dev/tty"; -} - - -#ifdef HAVE_TCGETATTR -static void -cleanup(void) -{ - if( restore_termios ) { - restore_termios = 0; /* do it prios in case it is interrupted again */ - if( tcsetattr(fileno(ttyfp), TCSAFLUSH, &termsave) ) - log_error("tcsetattr() failed: %s\n", strerror(errno) ); - } -} -#endif - -static void -init_ttyfp(void) -{ - if( initialized ) - return; - -#if defined(_WIN32) - { - SECURITY_ATTRIBUTES sa; - - memset(&sa, 0, sizeof(sa)); - sa.nLength = sizeof(sa); - sa.bInheritHandle = TRUE; - con.out = CreateFileA( "CONOUT$", GENERIC_READ|GENERIC_WRITE, - FILE_SHARE_READ|FILE_SHARE_WRITE, - &sa, OPEN_EXISTING, 0, 0 ); - if( con.out == INVALID_HANDLE_VALUE ) - log_fatal ("open(CONOUT$) failed: %s", w32_strerror (0)); - memset(&sa, 0, sizeof(sa)); - sa.nLength = sizeof(sa); - sa.bInheritHandle = TRUE; - con.in = CreateFileA( "CONIN$", GENERIC_READ|GENERIC_WRITE, - FILE_SHARE_READ|FILE_SHARE_WRITE, - &sa, OPEN_EXISTING, 0, 0 ); - if (con.in == INVALID_HANDLE_VALUE) - log_fatal ("open(CONIN$) failed: %s", w32_strerror (0)); - } - SetConsoleMode(con.in, DEF_INPMODE ); - SetConsoleMode(con.out, DEF_OUTMODE ); - -#elif defined(__EMX__) - ttyfp = stdout; /* Fixme: replace by the real functions: see wklib */ -#else - ttyfp = batchmode? stderr : fopen( tty_get_ttyname (), "r+"); - if( !ttyfp ) { - log_error("cannot open `%s': %s\n", - tty_get_ttyname (), strerror(errno) ); - exit(2); - } -#ifdef HAVE_LIBREADLINE - rl_catch_signals = 0; - rl_instream = rl_outstream = ttyfp; - rl_inhibit_completion = 1; -#endif -#endif -#ifdef HAVE_TCGETATTR - atexit( cleanup ); -#endif - initialized = 1; -} - -#ifdef HAVE_LIBREADLINE -void -tty_enable_completion(rl_completion_func_t *completer) -{ - if( no_terminal ) - return; - - if( !initialized ) - init_ttyfp(); - - rl_attempted_completion_function=completer; - rl_inhibit_completion=0; -} - -void -tty_disable_completion(void) -{ - if( no_terminal ) - return; - - if( !initialized ) - init_ttyfp(); - - rl_inhibit_completion=1; -} -#endif /*HAVE_LIBREADLINE*/ - -int -tty_batchmode( int onoff ) -{ - int old = batchmode; - if( onoff != -1 ) - batchmode = onoff; - return old; -} - -int -tty_no_terminal(int onoff) -{ - int old = no_terminal; - no_terminal = onoff ? 1 : 0; - return old; -} - -void -tty_printf( const char *fmt, ... ) -{ - va_list arg_ptr; - - if (no_terminal) - return; - - if( !initialized ) - init_ttyfp(); - - va_start( arg_ptr, fmt ) ; -#ifdef _WIN32 - { - char *buf = NULL; - int n; - DWORD nwritten; - - n = vasprintf(&buf, fmt, arg_ptr); - if( !buf ) - log_bug("vasprintf() failed\n"); - - if (!WriteConsoleA (con.out, buf, n, &nwritten, NULL)) - log_fatal ("WriteConsole failed: %s", w32_strerror (0)); - if( n != nwritten ) - log_fatal ("WriteConsole failed: %d != %d\n", n, (int)nwritten ); - last_prompt_len += n; - xfree (buf); - } -#else - last_prompt_len += vfprintf(ttyfp,fmt,arg_ptr) ; - fflush(ttyfp); -#endif - va_end(arg_ptr); -} - - -/* Same as tty_printf but if FP is not NULL, behave like the standard - fprintf. */ -void -tty_fprintf (FILE *fp, const char *fmt, ... ) -{ - va_list arg_ptr; - - if (fp) - { - va_start (arg_ptr, fmt) ; - vfprintf (fp, fmt, arg_ptr ); - va_end (arg_ptr); - return; - } - - if (no_terminal) - return; - - if( !initialized ) - init_ttyfp(); - - va_start( arg_ptr, fmt ) ; -#ifdef _WIN32 - { - char *buf = NULL; - int n; - DWORD nwritten; - - n = vasprintf(&buf, fmt, arg_ptr); - if( !buf ) - log_bug("vasprintf() failed\n"); - - if (!WriteConsoleA (con.out, buf, n, &nwritten, NULL)) - log_fatal ("WriteConsole failed: %s", w32_strerror (0)); - if (n != nwritten) - log_fatal ("WriteConsole failed: %d != %d\n", n, (int)nwritten); - last_prompt_len += n; - xfree (buf); - } -#else - last_prompt_len += vfprintf(ttyfp,fmt,arg_ptr) ; - fflush(ttyfp); -#endif - va_end(arg_ptr); -} - - -/**************** - * Print a string, but filter all control characters out. - */ -void -tty_print_string( const byte *p, size_t n ) -{ - if (no_terminal) - return; - - if( !initialized ) - init_ttyfp(); - -#ifdef _WIN32 - /* not so effective, change it if you want */ - for( ; n; n--, p++ ) - if( iscntrl( *p ) ) { - if( *p == '\n' ) - tty_printf("\\n"); - else if( !*p ) - tty_printf("\\0"); - else - tty_printf("\\x%02x", *p); - } - else - tty_printf("%c", *p); -#else - for( ; n; n--, p++ ) - if( iscntrl( *p ) ) { - putc('\\', ttyfp); - if( *p == '\n' ) - putc('n', ttyfp); - else if( !*p ) - putc('0', ttyfp); - else - fprintf(ttyfp, "x%02x", *p ); - } - else - putc(*p, ttyfp); -#endif -} - -void -tty_print_utf8_string2 (const byte *p, size_t n, size_t max_n ) -{ - size_t i; - char *buf; - - if (no_terminal) - return; - - /* we can handle plain ascii simpler, so check for it first */ - for(i=0; i < n; i++ ) { - if( p[i] & 0x80 ) - break; - } - if( i < n ) { - buf = utf8_to_native( p, n, 0 ); - if( max_n && (strlen( buf ) > max_n )) { - buf[max_n] = 0; - } - /*(utf8 conversion already does the control character quoting)*/ - tty_printf("%s", buf ); - xfree( buf ); - } - else { - if( max_n && (n > max_n) ) { - n = max_n; - } - tty_print_string( p, n ); - } -} - -void -tty_print_utf8_string( const byte *p, size_t n ) -{ - tty_print_utf8_string2( p, n, 0 ); -} - - -static char * -do_get( const char *prompt, int hidden ) -{ - char *buf; -#ifndef __riscos__ - byte cbuf[1]; -#endif - int c, n, i; - - if( batchmode ) { - log_error("Sorry, we are in batchmode - can't get input\n"); - exit(2); - } - - if (no_terminal) { - log_error("Sorry, no terminal at all requested - can't get input\n"); - exit(2); - } - - if( !initialized ) - init_ttyfp(); - - last_prompt_len = 0; - buf = xmalloc(n=50); - i = 0; - -#ifdef _WIN32 /* windoze version */ - if( hidden ) - SetConsoleMode(con.in, HID_INPMODE ); - - tty_printf( "%s", prompt ); - - for(;;) { - DWORD nread; - - if (!ReadConsoleA (con.in, cbuf, 1, &nread, NULL)) - log_fatal ("ReadConsole failed: %s", w32_strerror (0)); - if( !nread ) - continue; - if( *cbuf == '\n' ) - break; - - if( !hidden ) - last_prompt_len++; - c = *cbuf; - if( c == '\t' ) - c = ' '; - else if( c > 0xa0 ) - ; /* we don't allow 0xa0, as this is a protected blank which may - * confuse the user */ - else if( iscntrl(c) ) - continue; - if( !(i < n-1) ) { - n += 50; - buf = xrealloc( buf, n ); - } - buf[i++] = c; - } - - if( hidden ) - SetConsoleMode(con.in, DEF_INPMODE ); - -#elif defined(__riscos__) - tty_printf( "%s", prompt ); - do { - c = riscos_getchar(); - if (c == 0xa || c == 0xd) { /* Return || Enter */ - c = (int) '\n'; - } else if (c == 0x8 || c == 0x7f) { /* Backspace || Delete */ - if (i>0) { - i--; - if (!hidden) { - last_prompt_len--; - fputc(8, ttyfp); - fputc(32, ttyfp); - fputc(8, ttyfp); - fflush(ttyfp); - } - } else { - fputc(7, ttyfp); - fflush(ttyfp); - } - continue; - } else if (c == (int) '\t') { /* Tab */ - c = ' '; - } else if (c > 0xa0) { - ; /* we don't allow 0xa0, as this is a protected blank which may - * confuse the user */ - } else if (iscntrl(c)) { - continue; - } - if(!(i < n-1)) { - n += 50; - buf = xrealloc(buf, n); - } - buf[i++] = c; - if (!hidden) { - last_prompt_len++; - fputc(c, ttyfp); - fflush(ttyfp); - } - } while (c != '\n'); - i = (i>0) ? i-1 : 0; -#else /* unix version */ - if( hidden ) { -#ifdef HAVE_TCGETATTR - struct termios term; - - if( tcgetattr(fileno(ttyfp), &termsave) ) - log_fatal("tcgetattr() failed: %s\n", strerror(errno) ); - restore_termios = 1; - term = termsave; - term.c_lflag &= ~(ECHO | ECHOE | ECHOK | ECHONL); - if( tcsetattr( fileno(ttyfp), TCSAFLUSH, &term ) ) - log_fatal("tcsetattr() failed: %s\n", strerror(errno) ); -#endif - } - - tty_printf( "%s", prompt ); - - /* fixme: How can we avoid that the \n is echoed w/o disabling - * canonical mode - w/o this kill_prompt can't work */ - while( read(fileno(ttyfp), cbuf, 1) == 1 && *cbuf != '\n' ) { - if( !hidden ) - last_prompt_len++; - c = *cbuf; - if( c == CONTROL_D ) - log_info("control d found\n"); - if( c == '\t' ) - c = ' '; - else if( c > 0xa0 ) - ; /* we don't allow 0xa0, as this is a protected blank which may - * confuse the user */ - else if( iscntrl(c) ) - continue; - if( !(i < n-1) ) { - n += 50; - buf = xrealloc( buf, n ); - } - buf[i++] = c; - } - if( *cbuf != '\n' ) { - buf[0] = CONTROL_D; - i = 1; - } - - - if( hidden ) { -#ifdef HAVE_TCGETATTR - if( tcsetattr(fileno(ttyfp), TCSAFLUSH, &termsave) ) - log_error("tcsetattr() failed: %s\n", strerror(errno) ); - restore_termios = 0; -#endif - } -#endif /* end unix version */ - buf[i] = 0; - return buf; -} - - -char * -tty_get( const char *prompt ) -{ -#ifdef HAVE_LIBREADLINE - if (!batchmode && !no_terminal) { - char *line; - char *buf; - - if( !initialized ) - init_ttyfp(); - - last_prompt_len = 0; - - line = readline (prompt?prompt:""); - - /* We need to copy it to memory controlled by our malloc - implementations; further we need to convert an EOF to our - convention. */ - buf = xmalloc(line? strlen(line)+1:2); - if (line) - { - strcpy (buf, line); - trim_spaces (buf); - if (strlen (buf) > 2 ) - add_history (line); /* Note that we test BUF but add LINE. */ - free (line); - } - else - { - buf[0] = CONTROL_D; - buf[1] = 0; - } - return buf; - } - else -#endif /* HAVE_LIBREADLINE */ - return do_get( prompt, 0 ); -} - -char * -tty_get_hidden( const char *prompt ) -{ - return do_get( prompt, 1 ); -} - - -void -tty_kill_prompt() -{ - if ( no_terminal ) - return; - - if( !initialized ) - init_ttyfp(); - - if( batchmode ) - last_prompt_len = 0; - if( !last_prompt_len ) - return; -#ifdef _WIN32 - tty_printf("\r%*s\r", last_prompt_len, ""); -#else - { - int i; - putc('\r', ttyfp); - for(i=0; i < last_prompt_len; i ++ ) - putc(' ', ttyfp); - putc('\r', ttyfp); - fflush(ttyfp); - } -#endif - last_prompt_len = 0; -} - - -int -tty_get_answer_is_yes( const char *prompt ) -{ - int yes; - char *p = tty_get( prompt ); - tty_kill_prompt(); - yes = answer_is_yes(p); - xfree(p); - return yes; -} diff --git a/util/w32reg.c b/util/w32reg.c deleted file mode 100644 index f65c9542c..000000000 --- a/util/w32reg.c +++ /dev/null @@ -1,181 +0,0 @@ -/* w32reg.c - MS-Windows Registry access - * Copyright (C) 1999, 2002, 2005 Free Software Foundation, Inc. - * - * This file is part of GnuPG. - * - * GnuPG is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * GnuPG is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, - * USA. - */ - -#include <config.h> -#if defined (_WIN32) || defined (__CYGWIN32__) - /* This module is only used in this environment */ - -#include <stdio.h> -#include <stdlib.h> -#include <string.h> -#include <stdarg.h> -#include <windows.h> -#include "util.h" -#include "memory.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. - * NOTE: The value is allocated with a plain malloc() - use free() and not - * the usual xfree()!!! - */ -char * -read_w32_registry_string( const char *root, const char *dir, const char *name ) -{ - 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 direct */ - /* 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, so return direct */ - } - - nbytes = 1; - if( RegQueryValueEx( key_handle, name, 0, NULL, NULL, &nbytes ) ) { - if (root) - goto leave; - /* Try to fallback to HKLM also vor a missing value. */ - RegCloseKey (key_handle); - if (RegOpenKeyEx (HKEY_LOCAL_MACHINE, dir, 0, KEY_READ, &key_handle) ) - return NULL; /* Nope. */ - if (RegQueryValueEx( key_handle, name, 0, NULL, NULL, &nbytes)) - goto leave; - } - result = malloc( (n1=nbytes+1) ); - if( !result ) - goto leave; - if( RegQueryValueEx( key_handle, name, 0, &type, result, &n1 ) ) { - free(result); result = NULL; - goto leave; - } - result[nbytes] = 0; /* make sure it is really a string */ - if (type == REG_EXPAND_SZ && strchr (result, '%')) { - char *tmp; - - n1 += 1000; - tmp = malloc (n1+1); - if (!tmp) - goto leave; - nbytes = ExpandEnvironmentStrings (result, tmp, n1); - if (nbytes && nbytes > n1) { - free (tmp); - n1 = nbytes; - tmp = malloc (n1 + 1); - if (!tmp) - goto leave; - nbytes = ExpandEnvironmentStrings (result, tmp, n1); - if (nbytes && nbytes > n1) { - free (tmp); /* oops - truncated, better don't expand at all */ - goto leave; - } - tmp[nbytes] = 0; - free (result); - result = tmp; - } - else if (nbytes) { /* okay, reduce the length */ - tmp[nbytes] = 0; - free (result); - result = malloc (strlen (tmp)+1); - if (!result) - result = tmp; - else { - strcpy (result, tmp); - free (tmp); - } - } - else { /* error - don't expand */ - free (tmp); - } - } - - leave: - RegCloseKey( key_handle ); - return result; -} - - -int -write_w32_registry_string(const char *root, const char *dir, - const char *name, const char *value) -{ - HKEY root_key, reg_key; - - if ( !(root_key = get_root_key(root) ) ) - return -1; - - if ( RegOpenKeyEx( root_key, dir, 0, KEY_WRITE, ®_key ) - != ERROR_SUCCESS ) - return -1; - - if ( RegSetValueEx( reg_key, name, 0, REG_SZ, (BYTE *)value, - strlen( value ) ) != ERROR_SUCCESS ) { - if ( RegCreateKey( root_key, name, ®_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 /* __MINGW32__ || __CYGWIN32__ */ |
