diff -rN -u old-uim/configure.ac new-uim/configure.ac --- old-uim/configure.ac Fri Mar 30 00:58:09 2007 +++ new-uim/configure.ac Fri Mar 30 00:58:09 2007 @@ -347,7 +347,7 @@ AC_CHECK_FUNCS([asprintf vasprintf]) # C99 functions AC_CHECK_FUNCS([snprintf vsnprintf]) -AC_REPLACE_FUNCS([getpeereid strsep setenv unsetenv strlcpy strlcat]) +AC_REPLACE_FUNCS([getpeereid strsep setenv unsetenv strlcpy strlcat strtonum]) AC_CHECK_FUNCS([getpid stat mkdir chmod]) AC_CHECK_FUNCS([execv execvp]) AC_CHECK_FUNCS([isascii]) @@ -368,30 +368,72 @@ AC_DEFINE(HAVE_CONST_GAI_STRERROR_PROTO, 1, [Define if gai_strerror() returns const char *])])]) -AC_CACHE_CHECK([for C99 vsnprintf], uim_cv_HAVE_C99_VSNPRINTF,[ -AC_TRY_RUN([ +# Check for broken snprintf +if test "x$ac_cv_func_snprintf" = "xyes" ; then + AC_MSG_CHECKING([whether snprintf correctly terminates long strings]) + AC_RUN_IFELSE( + [AC_LANG_SOURCE([[ +#include +int main(void){char b[5];snprintf(b,5,"123456789");exit(b[4]!='\0');} + ]])], + [AC_MSG_RESULT(yes)], + [ + AC_MSG_RESULT(no) + AC_DEFINE(BROKEN_SNPRINTF, 1, + [Define if your snprintf is busted]) + AC_MSG_WARN([****** Your snprintf() function is broken, complain to your vendor]) + ], + [ AC_MSG_WARN([cross compiling: Assuming working snprintf()]) ] + ) +fi + +# If we don't have a working asprintf, then we strongly depend on vsnprintf +# returning the right thing on overflow: the number of characters it tried to +# create (as per SUSv3) +if test "x$ac_cv_func_asprintf" != "xyes" && \ + test "x$ac_cv_func_vsnprintf" = "xyes" ; then + AC_MSG_CHECKING([whether vsnprintf returns correct values on overflow]) + AC_RUN_IFELSE( + [AC_LANG_SOURCE([[ #include +#include #include -void foo(const char *format, ...) { - va_list ap; - int len; - char buf[5]; - va_start(ap, format); - len = vsnprintf(0, 0, format, ap); - va_end(ap); - if (len != 5) exit(1); - - if (snprintf(buf, 3, "hello") != 5 || strcmp(buf, "he") != 0) exit(1); - - exit(0); +int x_snprintf(char *str,size_t count,const char *fmt,...) +{ + size_t ret; va_list ap; + va_start(ap, fmt); ret = vsnprintf(str, count, fmt, ap); va_end(ap); + return ret; } -main() { foo("hello"); } -], -uim_cv_HAVE_C99_VSNPRINTF=yes,uim_cv_HAVE_C99_VSNPRINTF=no,uim_cv_HAVE_C99_VSNPRINTF=cross)]) -if test x"$uim_cv_HAVE_C99_VSNPRINTF" = x"yes"; then - AC_DEFINE(HAVE_C99_VSNPRINTF, 1, [define if you have vsnprintf with C99 semantics (set by configure)]) +int main(void) +{ + char x[1]; + exit(x_snprintf(x, 1, "%s %d", "hello", 12345) == 11 ? 0 : 1); +} ]])], + [AC_MSG_RESULT(yes)], + [ + AC_MSG_RESULT(no) + AC_DEFINE(BROKEN_SNPRINTF, 1, + [Define if your snprintf is busted]) + AC_MSG_WARN([****** Your vsnprintf() function is broken, complain to your vendor]) + ], + [ AC_MSG_WARN([cross compiling: Assuming working vsnprintf()]) ] + ) fi + +# On systems where [v]snprintf is broken, but is declared in stdio, +# check that the fmt argument is const char * or just char *. +# This is only useful for when BROKEN_SNPRINTF +AC_MSG_CHECKING([whether snprintf can declare const char *fmt]) +AC_COMPILE_IFELSE([AC_LANG_SOURCE([[#include + int snprintf(char *a, size_t b, const char *c, ...) { return 0; } + int main(void) { snprintf(0, 0, 0); } + ]])], + [AC_MSG_RESULT(yes) + AC_DEFINE(SNPRINTF_CONST, [const], + [Define as const if snprintf() can declare const char *fmt])], + [AC_MSG_RESULT(no) + AC_DEFINE(SNPRINTF_CONST, [/* not const */])]) AC_SEARCH_LIBS(dlfunc,dl, [ diff -rN -u old-uim/fep/uim-fep.c new-uim/fep/uim-fep.c --- old-uim/fep/uim-fep.c Fri Mar 30 00:58:08 2007 +++ new-uim/fep/uim-fep.c Fri Mar 30 00:58:09 2007 @@ -223,6 +223,58 @@ return engine; } +static uim_bool +check_dir(const char *dir) +{ + struct stat st; + + if (dir == NULL) + return UIM_FALSE; + + if (stat(dir, &st) < 0) + return (mkdir(dir, 0700) < 0) ? UIM_FALSE : UIM_TRUE; + else { + mode_t mode = S_IFDIR | S_IRUSR | S_IWUSR | S_IXUSR; + return ((st.st_mode & mode) == mode) ? UIM_TRUE : UIM_FALSE; + } +} + +static char * +get_ud_path(void) +{ + char *path, *home = NULL; + struct passwd *pw; + + pw = getpwuid(getuid()); + if (pw) + home = pw->pw_dir; + + if (!home && !uim_helper_is_setugid()) + home = getenv("HOME"); + + if (!home) + return NULL; + + if (asprintf(&path, "%s/.uim.d", home) == -1) + return NULL; /* XXX: fatal */ + + if (!check_dir(path)) { + free(path); + return NULL; + } + free(path); + + if (asprintf(&path, "%s/.uim.d/fep", home) == -1) + return NULL; /* XXX: fatal */ + + if (!check_dir(path)) { + free(path); + return NULL; + } + + return path; +} + int main(int argc, char **argv) { /* command will be execed on pty */ @@ -230,7 +282,7 @@ char *engine; char *sock_path = NULL; /* Socket for backtick */ int gnu_screen = FALSE; - char *env_buf; + char pid_str[30]; struct attribute_tag attr_uim = { FALSE, /* underline */ FALSE, /* standout */ @@ -241,10 +293,11 @@ }; FILE *fp; const char *suffix = NULL; - const char *tmp_dir; + const char *uim_dir; const char *sty_str; const char *win_str; struct stat stat_buf; + const char *errstr; int op; @@ -332,7 +385,11 @@ break; case 'w': - g_opt.statusline_width = atoi(optarg); + g_opt.statusline_width = strtonum(optarg, 1, 10000, &errstr); + if (errstr) { + printf("'%s' is %s", optarg, errstr); + return EXIT_FAILURE; + } if (g_opt.statusline_width <= 0) { usage(); return EXIT_FAILURE; @@ -408,8 +465,9 @@ tcgetattr(g_win_in, &s_save_tios); setupterm(NULL, g_win_out, NULL); - if ((tmp_dir = getenv("TMP")) == NULL) { - tmp_dir = "/tmp"; + if ((uim_dir = get_ud_path()) == NULL) { + sendline("uim-fep cannot make directory"); + return EXIT_FAILURE; } sty_str = getenv("STY"); @@ -419,65 +477,62 @@ puts("STY and WINDOW are not defined"); return EXIT_FAILURE; } - snprintf(s_path_getmode, sizeof(s_path_getmode), "%s/uim-fep-getmode-%s-%s", tmp_dir, sty_str, win_str); - snprintf(s_path_setmode, sizeof(s_path_setmode), "%s/uim-fep-setmode-%s-%s", tmp_dir, sty_str, win_str); + snprintf(s_path_getmode, sizeof(s_path_getmode), "%s/getmode-%s-%s", uim_dir, sty_str, win_str); + snprintf(s_path_setmode, sizeof(s_path_setmode), "%s/setmode-%s-%s", uim_dir, sty_str, win_str); if (stat(s_path_getmode, &stat_buf) == 0 || stat(s_path_setmode, &stat_buf) == 0) { char msg[100]; - snprintf(msg, 100, "uim-fep is already running on window %s", win_str); + snprintf(msg, sizeof(msg), "uim-fep is already running on window %s", win_str); sendline(msg); return EXIT_FAILURE; } if (suffix != NULL) { - snprintf(s_path_getmode, sizeof(s_path_getmode), "%s/uim-fep-getmode-%s", tmp_dir, suffix); - snprintf(s_path_setmode, sizeof(s_path_setmode), "%s/uim-fep-setmode-%s", tmp_dir, suffix); + snprintf(s_path_getmode, sizeof(s_path_getmode), "%s/getmode-%s", uim_dir, suffix); + snprintf(s_path_setmode, sizeof(s_path_setmode), "%s/setmode-%s", uim_dir, suffix); } else { - snprintf(s_path_getmode, sizeof(s_path_getmode), "%s/uim-fep-getmode-%s-%s-screen", tmp_dir, sty_str, win_str); - snprintf(s_path_setmode, sizeof(s_path_setmode), "%s/uim-fep-setmode-%s-%s-screen", tmp_dir, sty_str, win_str); + snprintf(s_path_getmode, sizeof(s_path_getmode), "%s/getmode-%s-%s-screen", uim_dir, sty_str, win_str); + snprintf(s_path_setmode, sizeof(s_path_setmode), "%s/setmode-%s-%s-screen", uim_dir, sty_str, win_str); } } else { if (sty_str != NULL && win_str != NULL) { - snprintf(s_path_getmode, sizeof(s_path_getmode), "%s/uim-fep-getmode-%s-%s-screen", tmp_dir, sty_str, win_str); - snprintf(s_path_setmode, sizeof(s_path_setmode), "%s/uim-fep-setmode-%s-%s-screen", tmp_dir, sty_str, win_str); + snprintf(s_path_getmode, sizeof(s_path_getmode), "%s/getmode-%s-%s-screen", uim_dir, sty_str, win_str); + snprintf(s_path_setmode, sizeof(s_path_setmode), "%s/setmode-%s-%s-screen", uim_dir, sty_str, win_str); if (stat(s_path_getmode, &stat_buf) == 0 || stat(s_path_setmode, &stat_buf) == 0) { printf("uim-fep is already running on window %s as filter\n", win_str); return EXIT_FAILURE; } if (suffix != NULL) { - snprintf(s_path_getmode, sizeof(s_path_getmode), "%s/uim-fep-getmode-%s", tmp_dir, suffix); - snprintf(s_path_setmode, sizeof(s_path_setmode), "%s/uim-fep-setmode-%s", tmp_dir, suffix); + snprintf(s_path_getmode, sizeof(s_path_getmode), "%s/getmode-%s", uim_dir, suffix); + snprintf(s_path_setmode, sizeof(s_path_setmode), "%s/setmode-%s", uim_dir, suffix); } else { - snprintf(s_path_getmode, sizeof(s_path_getmode), "%s/uim-fep-getmode-%s-%s", tmp_dir, sty_str, win_str); - snprintf(s_path_setmode, sizeof(s_path_setmode), "%s/uim-fep-setmode-%s-%s", tmp_dir, sty_str, win_str); + snprintf(s_path_getmode, sizeof(s_path_getmode), "%s/getmode-%s-%s", uim_dir, sty_str, win_str); + snprintf(s_path_setmode, sizeof(s_path_setmode), "%s/setmode-%s-%s", uim_dir, sty_str, win_str); } } else { if (suffix != NULL) { - snprintf(s_path_getmode, sizeof(s_path_getmode), "%s/uim-fep-getmode-%s", tmp_dir, suffix); - snprintf(s_path_setmode, sizeof(s_path_setmode), "%s/uim-fep-setmode-%s", tmp_dir, suffix); + snprintf(s_path_getmode, sizeof(s_path_getmode), "%s/getmode-%s", uim_dir, suffix); + snprintf(s_path_setmode, sizeof(s_path_setmode), "%s/setmode-%s", uim_dir, suffix); } else { int file_suffix = 1; int pid = getpid(); - snprintf(s_path_getmode, sizeof(s_path_getmode), "%s/uim-fep-getmode-%d", tmp_dir, pid); - snprintf(s_path_setmode, sizeof(s_path_setmode), "%s/uim-fep-setmode-%d", tmp_dir, pid); + snprintf(s_path_getmode, sizeof(s_path_getmode), "%s/getmode-%d", uim_dir, pid); + snprintf(s_path_setmode, sizeof(s_path_setmode), "%s/setmode-%d", uim_dir, pid); while (stat(s_path_getmode, &stat_buf) == 0 || stat(s_path_setmode, &stat_buf) == 0) { - snprintf(s_path_getmode, sizeof(s_path_getmode), "%s/uim-fep-getmode-%d-%d", tmp_dir, pid, file_suffix); - snprintf(s_path_setmode, sizeof(s_path_setmode), "%s/uim-fep-setmode-%d-%d", tmp_dir, pid, file_suffix); + snprintf(s_path_getmode, sizeof(s_path_getmode), "%s/getmode-%d-%d", uim_dir, pid, file_suffix); + snprintf(s_path_setmode, sizeof(s_path_setmode), "%s/setmode-%d-%d", uim_dir, pid, file_suffix); file_suffix++; } } } } - env_buf = malloc(30); - snprintf(env_buf, 30, "UIM_FEP_PID=%d", getpid()); - putenv(env_buf); + snprintf(pid_str, sizeof(pid_str), "%d", getpid()); + setenv("UIM_FEP_PID", pid_str, 1); if ((fp = fopen(s_path_getmode, "wt")) != NULL) { fclose(fp); unlink(s_path_getmode); - env_buf = malloc(strlen("UIM_FEP_GETMODE=") + strlen(s_path_getmode) + 1); - sprintf(env_buf, "UIM_FEP_GETMODE=%s", s_path_getmode); - putenv(env_buf); + setenv("UIM_FEP_GETMODE", s_path_getmode, 1); } else { s_path_getmode[0] = '\0'; } @@ -485,9 +540,7 @@ unlink(s_path_setmode); if (mkfifo(s_path_setmode, 0600) != -1) { unlink(s_path_setmode); - env_buf = malloc(strlen("UIM_FEP_SETMODE=") + strlen(s_path_setmode) + 1); - sprintf(env_buf, "UIM_FEP_SETMODE=%s", s_path_setmode); - putenv(env_buf); + setenv("UIM_FEP_SETMODE", s_path_setmode, 1); } else { s_path_setmode[0] = '\0'; s_setmode_fd = -1; @@ -730,6 +783,7 @@ int nfd; char *_clear_screen = cut_padding(clear_screen); char *_clr_eos = cut_padding(clr_eos); + const char *errstr; if (g_win_in > s_master) { if (g_win_in > s_setmode_fd) { @@ -830,8 +884,10 @@ for (start = end; start > 0 && isdigit((unsigned char)buf[start - 1]); --start); buf[end + 1] = '\0'; - mode = atoi(&buf[start]); - if (mode != uim_get_current_mode(g_context)) { + mode = strtonum(&buf[start], 0, uim_get_nr_modes(g_context) - 1, &errstr); + if (errstr) { + debug2(("error: '%s' is %s\n", &buf[start], errstr)); + } else if (mode != uim_get_current_mode(g_context)) { debug2(("mode change %d\n", mode)); uim_set_mode(g_context, mode); /* callbacks_set_mode(uim_get_current_mode(g_context)); */ diff -rN -u old-uim/replace/Makefile.am new-uim/replace/Makefile.am --- old-uim/replace/Makefile.am Fri Mar 30 00:58:08 2007 +++ new-uim/replace/Makefile.am Fri Mar 30 00:58:09 2007 @@ -1,2 +1,2 @@ noinst_LTLIBRARIES = libreplace.la -libreplace_la_SOURCES = strsep.c getpeereid.c setenv.c os_dep.h strlcpy.c strlcat.c fake-rfc2553.c fake-rfc2553.h +libreplace_la_SOURCES = strsep.c getpeereid.c setenv.c os_dep.h strlcpy.c strlcat.c fake-rfc2553.c fake-rfc2553.h bsd-asprintf.c bsd-snprintf.c strtonum.c diff -rN -u old-uim/replace/bsd-asprintf.c new-uim/replace/bsd-asprintf.c --- old-uim/replace/bsd-asprintf.c Thu Jan 1 09:00:00 1970 +++ new-uim/replace/bsd-asprintf.c Fri Mar 30 00:58:09 2007 @@ -0,0 +1,99 @@ +/* + * Copyright (c) 2004 Darren Tucker. + * + * Based originally on asprintf.c from OpenBSD: + * Copyright (c) 1997 Todd C. Miller + * + * Permission to use, copy, modify, and distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + +#include + +#ifndef HAVE_VASPRINTF + +#include +#include +#include + +#ifndef VA_COPY +# ifdef HAVE_VA_COPY +# define VA_COPY(dest, src) va_copy(dest, src) +# else +# ifdef HAVE___VA_COPY +# define VA_COPY(dest, src) __va_copy(dest, src) +# else +# define VA_COPY(dest, src) (dest) = (src) +# endif +# endif +#endif + +#define INIT_SZ 128 + +int vasprintf(char **str, const char *fmt, va_list ap) +{ + int ret = -1; + va_list ap2; + char *string, *newstr; + size_t len; + + VA_COPY(ap2, ap); + if ((string = malloc(INIT_SZ)) == NULL) + goto fail; + + ret = vsnprintf(string, INIT_SZ, fmt, ap2); + if (ret >= 0 && ret < INIT_SZ) { /* succeeded with initial alloc */ + *str = string; + } else if (ret == INT_MAX) { /* shouldn't happen */ + goto fail; + } else { /* bigger than initial, realloc allowing for nul */ + len = (size_t)ret + 1; + if ((newstr = realloc(string, len)) == NULL) { + free(string); + goto fail; + } else { + va_end(ap2); + VA_COPY(ap2, ap); + ret = vsnprintf(newstr, len, fmt, ap2); + if (ret >= 0 && (size_t)ret < len) { + *str = newstr; + } else { /* failed with realloc'ed string, give up */ + free(newstr); + goto fail; + } + } + } + va_end(ap2); + return (ret); + +fail: + *str = NULL; + errno = ENOMEM; + va_end(ap2); + return (-1); +} +#endif + +#ifndef HAVE_ASPRINTF +int asprintf(char **str, const char *fmt, ...) +{ + va_list ap; + int ret; + + *str = NULL; + va_start(ap, fmt); + ret = vasprintf(str, fmt, ap); + va_end(ap); + + return ret; +} +#endif diff -rN -u old-uim/replace/bsd-snprintf.c new-uim/replace/bsd-snprintf.c --- old-uim/replace/bsd-snprintf.c Thu Jan 1 09:00:00 1970 +++ new-uim/replace/bsd-snprintf.c Fri Mar 30 00:58:09 2007 @@ -0,0 +1,805 @@ +/* + * Copyright Patrick Powell 1995 + * This code is based on code written by Patrick Powell (papowell@astart.com) + * It may be used for any purpose as long as this notice remains intact + * on all source code distributions + */ + +/************************************************************** + * Original: + * Patrick Powell Tue Apr 11 09:48:21 PDT 1995 + * A bombproof version of doprnt (dopr) included. + * Sigh. This sort of thing is always nasty do deal with. Note that + * the version here does not include floating point... + * + * snprintf() is used instead of sprintf() as it does limit checks + * for string length. This covers a nasty loophole. + * + * The other functions are there to prevent NULL pointers from + * causing nast effects. + * + * More Recently: + * Brandon Long 9/15/96 for mutt 0.43 + * This was ugly. It is still ugly. I opted out of floating point + * numbers, but the formatter understands just about everything + * from the normal C string format, at least as far as I can tell from + * the Solaris 2.5 printf(3S) man page. + * + * Brandon Long 10/22/97 for mutt 0.87.1 + * Ok, added some minimal floating point support, which means this + * probably requires libm on most operating systems. Don't yet + * support the exponent (e,E) and sigfig (g,G). Also, fmtint() + * was pretty badly broken, it just wasn't being exercised in ways + * which showed it, so that's been fixed. Also, formated the code + * to mutt conventions, and removed dead code left over from the + * original. Also, there is now a builtin-test, just compile with: + * gcc -DTEST_SNPRINTF -o snprintf snprintf.c -lm + * and run snprintf for results. + * + * Thomas Roessler 01/27/98 for mutt 0.89i + * The PGP code was using unsigned hexadecimal formats. + * Unfortunately, unsigned formats simply didn't work. + * + * Michael Elkins 03/05/98 for mutt 0.90.8 + * The original code assumed that both snprintf() and vsnprintf() were + * missing. Some systems only have snprintf() but not vsnprintf(), so + * the code is now broken down under HAVE_SNPRINTF and HAVE_VSNPRINTF. + * + * Andrew Tridgell (tridge@samba.org) Oct 1998 + * fixed handling of %.0f + * added test for HAVE_LONG_DOUBLE + * + * tridge@samba.org, idra@samba.org, April 2001 + * got rid of fcvt code (twas buggy and made testing harder) + * added C99 semantics + * + * date: 2002/12/19 19:56:31; author: herb; state: Exp; lines: +2 -0 + * actually print args for %g and %e + * + * date: 2002/06/03 13:37:52; author: jmcd; state: Exp; lines: +8 -0 + * Since includes.h isn't included here, VA_COPY has to be defined here. I don't + * see any include file that is guaranteed to be here, so I'm defining it + * locally. Fixes AIX and Solaris builds. + * + * date: 2002/06/03 03:07:24; author: tridge; state: Exp; lines: +5 -13 + * put the ifdef for HAVE_VA_COPY in one place rather than in lots of + * functions + * + * date: 2002/05/17 14:51:22; author: jmcd; state: Exp; lines: +21 -4 + * Fix usage of va_list passed as an arg. Use __va_copy before using it + * when it exists. + * + * date: 2002/04/16 22:38:04; author: idra; state: Exp; lines: +20 -14 + * Fix incorrect zpadlen handling in fmtfp. + * Thanks to Ollie Oldham for spotting it. + * few mods to make it easier to compile the tests. + * addedd the "Ollie" test to the floating point ones. + * + * Martin Pool (mbp@samba.org) April 2003 + * Remove NO_CONFIG_H so that the test case can be built within a source + * tree with less trouble. + * Remove unnecessary SAFE_FREE() definition. + * + * Martin Pool (mbp@samba.org) May 2003 + * Put in a prototype for dummy_snprintf() to quiet compiler warnings. + * + * Move #endif to make sure VA_COPY, LDOUBLE, etc are defined even + * if the C library has some snprintf functions already. + **************************************************************/ + +#include + +#if defined(BROKEN_SNPRINTF) /* For those with broken snprintf() */ +# undef HAVE_SNPRINTF +# undef HAVE_VSNPRINTF +#endif + +#ifndef VA_COPY +# ifdef HAVE_VA_COPY +# define VA_COPY(dest, src) va_copy(dest, src) +# else +# ifdef HAVE___VA_COPY +# define VA_COPY(dest, src) __va_copy(dest, src) +# else +# define VA_COPY(dest, src) (dest) = (src) +# endif +# endif +#endif + +#if !defined(HAVE_SNPRINTF) || !defined(HAVE_VSNPRINTF) + +#include +#include +#include +#include + +#ifdef HAVE_LONG_DOUBLE +# define LDOUBLE long double +#else +# define LDOUBLE double +#endif + +#ifdef HAVE_LONG_LONG +# define LLONG long long +#else +# define LLONG long +#endif + +/* + * dopr(): poor man's version of doprintf + */ + +/* format read states */ +#define DP_S_DEFAULT 0 +#define DP_S_FLAGS 1 +#define DP_S_MIN 2 +#define DP_S_DOT 3 +#define DP_S_MAX 4 +#define DP_S_MOD 5 +#define DP_S_CONV 6 +#define DP_S_DONE 7 + +/* format flags - Bits */ +#define DP_F_MINUS (1 << 0) +#define DP_F_PLUS (1 << 1) +#define DP_F_SPACE (1 << 2) +#define DP_F_NUM (1 << 3) +#define DP_F_ZERO (1 << 4) +#define DP_F_UP (1 << 5) +#define DP_F_UNSIGNED (1 << 6) + +/* Conversion Flags */ +#define DP_C_SHORT 1 +#define DP_C_LONG 2 +#define DP_C_LDOUBLE 3 +#define DP_C_LLONG 4 + +#define char_to_int(p) ((p)- '0') +#ifndef MAX +# define MAX(p,q) (((p) >= (q)) ? (p) : (q)) +#endif + +static size_t dopr(char *buffer, size_t maxlen, const char *format, + va_list args_in); +static void fmtstr(char *buffer, size_t *currlen, size_t maxlen, + char *value, int flags, int min, int max); +static void fmtint(char *buffer, size_t *currlen, size_t maxlen, + LLONG value, int base, int min, int max, int flags); +static void fmtfp(char *buffer, size_t *currlen, size_t maxlen, + LDOUBLE fvalue, int min, int max, int flags); +static void dopr_outch(char *buffer, size_t *currlen, size_t maxlen, char c); + +static size_t dopr(char *buffer, size_t maxlen, const char *format, va_list args_in) +{ + char ch; + LLONG value; + LDOUBLE fvalue; + char *strvalue; + int min; + int max; + int state; + int flags; + int cflags; + size_t currlen; + va_list args; + + VA_COPY(args, args_in); + + state = DP_S_DEFAULT; + currlen = flags = cflags = min = 0; + max = -1; + ch = *format++; + + while (state != DP_S_DONE) { + if (ch == '\0') + state = DP_S_DONE; + + switch(state) { + case DP_S_DEFAULT: + if (ch == '%') + state = DP_S_FLAGS; + else + dopr_outch (buffer, &currlen, maxlen, ch); + ch = *format++; + break; + case DP_S_FLAGS: + switch (ch) { + case '-': + flags |= DP_F_MINUS; + ch = *format++; + break; + case '+': + flags |= DP_F_PLUS; + ch = *format++; + break; + case ' ': + flags |= DP_F_SPACE; + ch = *format++; + break; + case '#': + flags |= DP_F_NUM; + ch = *format++; + break; + case '0': + flags |= DP_F_ZERO; + ch = *format++; + break; + default: + state = DP_S_MIN; + break; + } + break; + case DP_S_MIN: + if (isdigit((unsigned char)ch)) { + min = 10*min + char_to_int (ch); + ch = *format++; + } else if (ch == '*') { + min = va_arg (args, int); + ch = *format++; + state = DP_S_DOT; + } else { + state = DP_S_DOT; + } + break; + case DP_S_DOT: + if (ch == '.') { + state = DP_S_MAX; + ch = *format++; + } else { + state = DP_S_MOD; + } + break; + case DP_S_MAX: + if (isdigit((unsigned char)ch)) { + if (max < 0) + max = 0; + max = 10*max + char_to_int (ch); + ch = *format++; + } else if (ch == '*') { + max = va_arg (args, int); + ch = *format++; + state = DP_S_MOD; + } else { + state = DP_S_MOD; + } + break; + case DP_S_MOD: + switch (ch) { + case 'h': + cflags = DP_C_SHORT; + ch = *format++; + break; + case 'l': + cflags = DP_C_LONG; + ch = *format++; + if (ch == 'l') { /* It's a long long */ + cflags = DP_C_LLONG; + ch = *format++; + } + break; + case 'L': + cflags = DP_C_LDOUBLE; + ch = *format++; + break; + default: + break; + } + state = DP_S_CONV; + break; + case DP_S_CONV: + switch (ch) { + case 'd': + case 'i': + if (cflags == DP_C_SHORT) + value = va_arg (args, int); + else if (cflags == DP_C_LONG) + value = va_arg (args, long int); + else if (cflags == DP_C_LLONG) + value = va_arg (args, LLONG); + else + value = va_arg (args, int); + fmtint (buffer, &currlen, maxlen, value, 10, min, max, flags); + break; + case 'o': + flags |= DP_F_UNSIGNED; + if (cflags == DP_C_SHORT) + value = va_arg (args, unsigned int); + else if (cflags == DP_C_LONG) + value = (long)va_arg (args, unsigned long int); + else if (cflags == DP_C_LLONG) + value = (long)va_arg (args, unsigned LLONG); + else + value = (long)va_arg (args, unsigned int); + fmtint (buffer, &currlen, maxlen, value, 8, min, max, flags); + break; + case 'u': + flags |= DP_F_UNSIGNED; + if (cflags == DP_C_SHORT) + value = va_arg (args, unsigned int); + else if (cflags == DP_C_LONG) + value = (long)va_arg (args, unsigned long int); + else if (cflags == DP_C_LLONG) + value = (LLONG)va_arg (args, unsigned LLONG); + else + value = (long)va_arg (args, unsigned int); + fmtint (buffer, &currlen, maxlen, value, 10, min, max, flags); + break; + case 'X': + flags |= DP_F_UP; + case 'x': + flags |= DP_F_UNSIGNED; + if (cflags == DP_C_SHORT) + value = va_arg (args, unsigned int); + else if (cflags == DP_C_LONG) + value = (long)va_arg (args, unsigned long int); + else if (cflags == DP_C_LLONG) + value = (LLONG)va_arg (args, unsigned LLONG); + else + value = (long)va_arg (args, unsigned int); + fmtint (buffer, &currlen, maxlen, value, 16, min, max, flags); + break; + case 'f': + if (cflags == DP_C_LDOUBLE) + fvalue = va_arg (args, LDOUBLE); + else + fvalue = va_arg (args, double); + /* um, floating point? */ + fmtfp (buffer, &currlen, maxlen, fvalue, min, max, flags); + break; + case 'E': + flags |= DP_F_UP; + case 'e': + if (cflags == DP_C_LDOUBLE) + fvalue = va_arg (args, LDOUBLE); + else + fvalue = va_arg (args, double); + fmtfp (buffer, &currlen, maxlen, fvalue, min, max, flags); + break; + case 'G': + flags |= DP_F_UP; + case 'g': + if (cflags == DP_C_LDOUBLE) + fvalue = va_arg (args, LDOUBLE); + else + fvalue = va_arg (args, double); + fmtfp (buffer, &currlen, maxlen, fvalue, min, max, flags); + break; + case 'c': + dopr_outch (buffer, &currlen, maxlen, va_arg (args, int)); + break; + case 's': + strvalue = va_arg (args, char *); + if (!strvalue) strvalue = "(NULL)"; + if (max == -1) { + max = strlen(strvalue); + } + if (min > 0 && max >= 0 && min > max) max = min; + fmtstr (buffer, &currlen, maxlen, strvalue, flags, min, max); + break; + case 'p': + strvalue = va_arg (args, void *); + fmtint (buffer, &currlen, maxlen, (long) strvalue, 16, min, max, flags); + break; + case 'n': + if (cflags == DP_C_SHORT) { + short int *num; + num = va_arg (args, short int *); + *num = currlen; + } else if (cflags == DP_C_LONG) { + long int *num; + num = va_arg (args, long int *); + *num = (long int)currlen; + } else if (cflags == DP_C_LLONG) { + LLONG *num; + num = va_arg (args, LLONG *); + *num = (LLONG)currlen; + } else { + int *num; + num = va_arg (args, int *); + *num = currlen; + } + break; + case '%': + dopr_outch (buffer, &currlen, maxlen, ch); + break; + case 'w': + /* not supported yet, treat as next char */ + ch = *format++; + break; + default: + /* Unknown, skip */ + break; + } + ch = *format++; + state = DP_S_DEFAULT; + flags = cflags = min = 0; + max = -1; + break; + case DP_S_DONE: + break; + default: + /* hmm? */ + break; /* some picky compilers need this */ + } + } + if (maxlen != 0) { + if (currlen < maxlen - 1) + buffer[currlen] = '\0'; + else if (maxlen > 0) + buffer[maxlen - 1] = '\0'; + } + + return currlen; +} + +static void fmtstr(char *buffer, size_t *currlen, size_t maxlen, + char *value, int flags, int min, int max) +{ + int padlen, strln; /* amount to pad */ + int cnt = 0; + +#ifdef DEBUG_SNPRINTF + printf("fmtstr min=%d max=%d s=[%s]\n", min, max, value); +#endif + if (value == 0) { + value = ""; + } + + for (strln = 0; strln < max && value[strln]; ++strln); /* strlen */ + padlen = min - strln; + if (padlen < 0) + padlen = 0; + if (flags & DP_F_MINUS) + padlen = -padlen; /* Left Justify */ + + while ((padlen > 0) && (cnt < max)) { + dopr_outch (buffer, currlen, maxlen, ' '); + --padlen; + ++cnt; + } + while (*value && (cnt < max)) { + dopr_outch (buffer, currlen, maxlen, *value++); + ++cnt; + } + while ((padlen < 0) && (cnt < max)) { + dopr_outch (buffer, currlen, maxlen, ' '); + ++padlen; + ++cnt; + } +} + +/* Have to handle DP_F_NUM (ie 0x and 0 alternates) */ + +static void fmtint(char *buffer, size_t *currlen, size_t maxlen, + LLONG value, int base, int min, int max, int flags) +{ + int signvalue = 0; + unsigned LLONG uvalue; + char convert[20]; + int place = 0; + int spadlen = 0; /* amount to space pad */ + int zpadlen = 0; /* amount to zero pad */ + int caps = 0; + + if (max < 0) + max = 0; + + uvalue = value; + + if(!(flags & DP_F_UNSIGNED)) { + if( value < 0 ) { + signvalue = '-'; + uvalue = -value; + } else { + if (flags & DP_F_PLUS) /* Do a sign (+/i) */ + signvalue = '+'; + else if (flags & DP_F_SPACE) + signvalue = ' '; + } + } + + if (flags & DP_F_UP) caps = 1; /* Should characters be upper case? */ + + do { + convert[place++] = + (caps? "0123456789ABCDEF":"0123456789abcdef") + [uvalue % (unsigned)base ]; + uvalue = (uvalue / (unsigned)base ); + } while(uvalue && (place < 20)); + if (place == 20) place--; + convert[place] = 0; + + zpadlen = max - place; + spadlen = min - MAX (max, place) - (signvalue ? 1 : 0); + if (zpadlen < 0) zpadlen = 0; + if (spadlen < 0) spadlen = 0; + if (flags & DP_F_ZERO) { + zpadlen = MAX(zpadlen, spadlen); + spadlen = 0; + } + if (flags & DP_F_MINUS) + spadlen = -spadlen; /* Left Justifty */ + +#ifdef DEBUG_SNPRINTF + printf("zpad: %d, spad: %d, min: %d, max: %d, place: %d\n", + zpadlen, spadlen, min, max, place); +#endif + + /* Spaces */ + while (spadlen > 0) { + dopr_outch (buffer, currlen, maxlen, ' '); + --spadlen; + } + + /* Sign */ + if (signvalue) + dopr_outch (buffer, currlen, maxlen, signvalue); + + /* Zeros */ + if (zpadlen > 0) { + while (zpadlen > 0) { + dopr_outch (buffer, currlen, maxlen, '0'); + --zpadlen; + } + } + + /* Digits */ + while (place > 0) + dopr_outch (buffer, currlen, maxlen, convert[--place]); + + /* Left Justified spaces */ + while (spadlen < 0) { + dopr_outch (buffer, currlen, maxlen, ' '); + ++spadlen; + } +} + +static LDOUBLE abs_val(LDOUBLE value) +{ + LDOUBLE result = value; + + if (value < 0) + result = -value; + + return result; +} + +static LDOUBLE POW10(int exp) +{ + LDOUBLE result = 1; + + while (exp) { + result *= 10; + exp--; + } + + return result; +} + +static LLONG ROUND(LDOUBLE value) +{ + LLONG intpart; + + intpart = (LLONG)value; + value = value - intpart; + if (value >= 0.5) intpart++; + + return intpart; +} + +/* a replacement for modf that doesn't need the math library. Should + be portable, but slow */ +static double my_modf(double x0, double *iptr) +{ + int i; + long l; + double x = x0; + double f = 1.0; + + for (i=0;i<100;i++) { + l = (long)x; + if (l <= (x+1) && l >= (x-1)) break; + x *= 0.1; + f *= 10.0; + } + + if (i == 100) { + /* yikes! the number is beyond what we can handle. What do we do? */ + (*iptr) = 0; + return 0; + } + + if (i != 0) { + double i2; + double ret; + + ret = my_modf(x0-l*f, &i2); + (*iptr) = l*f + i2; + return ret; + } + + (*iptr) = l; + return x - (*iptr); +} + + +static void fmtfp (char *buffer, size_t *currlen, size_t maxlen, + LDOUBLE fvalue, int min, int max, int flags) +{ + int signvalue = 0; + double ufvalue; + char iconvert[311]; + char fconvert[311]; + int iplace = 0; + int fplace = 0; + int padlen = 0; /* amount to pad */ + int zpadlen = 0; + int caps = 0; + int idx; + double intpart; + double fracpart; + double temp; + + /* + * AIX manpage says the default is 0, but Solaris says the default + * is 6, and sprintf on AIX defaults to 6 + */ + if (max < 0) + max = 6; + + ufvalue = abs_val (fvalue); + + if (fvalue < 0) { + signvalue = '-'; + } else { + if (flags & DP_F_PLUS) { /* Do a sign (+/i) */ + signvalue = '+'; + } else { + if (flags & DP_F_SPACE) + signvalue = ' '; + } + } + +#if 0 + if (flags & DP_F_UP) caps = 1; /* Should characters be upper case? */ +#endif + +#if 0 + if (max == 0) ufvalue += 0.5; /* if max = 0 we must round */ +#endif + + /* + * Sorry, we only support 16 digits past the decimal because of our + * conversion method + */ + if (max > 16) + max = 16; + + /* We "cheat" by converting the fractional part to integer by + * multiplying by a factor of 10 + */ + + temp = ufvalue; + my_modf(temp, &intpart); + + fracpart = ROUND((POW10(max)) * (ufvalue - intpart)); + + if (fracpart >= POW10(max)) { + intpart++; + fracpart -= POW10(max); + } + + /* Convert integer part */ + do { + temp = intpart*0.1; + my_modf(temp, &intpart); + idx = (int) ((temp -intpart +0.05)* 10.0); + /* idx = (int) (((double)(temp*0.1) -intpart +0.05) *10.0); */ + /* printf ("%llf, %f, %x\n", temp, intpart, idx); */ + iconvert[iplace++] = + (caps? "0123456789ABCDEF":"0123456789abcdef")[idx]; + } while (intpart && (iplace < 311)); + if (iplace == 311) iplace--; + iconvert[iplace] = 0; + + /* Convert fractional part */ + if (fracpart) + { + do { + temp = fracpart*0.1; + my_modf(temp, &fracpart); + idx = (int) ((temp -fracpart +0.05)* 10.0); + /* idx = (int) ((((temp/10) -fracpart) +0.05) *10); */ + /* printf ("%lf, %lf, %ld\n", temp, fracpart, idx ); */ + fconvert[fplace++] = + (caps? "0123456789ABCDEF":"0123456789abcdef")[idx]; + } while(fracpart && (fplace < 311)); + if (fplace == 311) fplace--; + } + fconvert[fplace] = 0; + + /* -1 for decimal point, another -1 if we are printing a sign */ + padlen = min - iplace - max - 1 - ((signvalue) ? 1 : 0); + zpadlen = max - fplace; + if (zpadlen < 0) zpadlen = 0; + if (padlen < 0) + padlen = 0; + if (flags & DP_F_MINUS) + padlen = -padlen; /* Left Justifty */ + + if ((flags & DP_F_ZERO) && (padlen > 0)) { + if (signvalue) { + dopr_outch (buffer, currlen, maxlen, signvalue); + --padlen; + signvalue = 0; + } + while (padlen > 0) { + dopr_outch (buffer, currlen, maxlen, '0'); + --padlen; + } + } + while (padlen > 0) { + dopr_outch (buffer, currlen, maxlen, ' '); + --padlen; + } + if (signvalue) + dopr_outch (buffer, currlen, maxlen, signvalue); + + while (iplace > 0) + dopr_outch (buffer, currlen, maxlen, iconvert[--iplace]); + +#ifdef DEBUG_SNPRINTF + printf("fmtfp: fplace=%d zpadlen=%d\n", fplace, zpadlen); +#endif + + /* + * Decimal point. This should probably use locale to find the correct + * char to print out. + */ + if (max > 0) { + dopr_outch (buffer, currlen, maxlen, '.'); + + while (zpadlen > 0) { + dopr_outch (buffer, currlen, maxlen, '0'); + --zpadlen; + } + + while (fplace > 0) + dopr_outch (buffer, currlen, maxlen, fconvert[--fplace]); + } + + while (padlen < 0) { + dopr_outch (buffer, currlen, maxlen, ' '); + ++padlen; + } +} + +static void dopr_outch(char *buffer, size_t *currlen, size_t maxlen, char c) +{ + if (*currlen < maxlen) { + buffer[(*currlen)] = c; + } + (*currlen)++; +} +#endif /* !defined(HAVE_SNPRINTF) || !defined(HAVE_VSNPRINTF) */ + +#if !defined(HAVE_VSNPRINTF) +int vsnprintf (char *str, size_t count, const char *fmt, va_list args) +{ + return dopr(str, count, fmt, args); +} +#endif + +#if !defined(HAVE_SNPRINTF) +int snprintf(char *str, size_t count, SNPRINTF_CONST char *fmt, ...) +{ + size_t ret; + va_list ap; + + va_start(ap, fmt); + ret = vsnprintf(str, count, fmt, ap); + va_end(ap); + return ret; +} +#endif + diff -rN -u old-uim/replace/os_dep.h new-uim/replace/os_dep.h --- old-uim/replace/os_dep.h Fri Mar 30 00:58:08 2007 +++ new-uim/replace/os_dep.h Fri Mar 30 00:58:09 2007 @@ -47,6 +47,9 @@ #if HAVE_SYS_TYPES_H #include #endif +#if HAVE_STDARG_H +#include +#endif #include #ifdef __cplusplus @@ -85,6 +88,31 @@ #endif #include "fake-rfc2553.h" + +#ifndef HAVE_VASPRINTF +#define vasprintf uim_vasprintf +int vasprintf(char **ret, const char *format, va_list ap); +#endif + +#ifndef HAVE_ASPRINTF +#define asprintf uim_asprintf +int asprintf(char **ret, const char *format, ...); +#endif + +#if !defined(HAVE_VSNPRINTF) || defined(BROKEN_SNPRINTF) +#define vsnprintf uim_vsnprintf +int vsnprintf(char *str, size_t size, const char *format, va_list ap); +#endif + +#if !defined(HAVE_SNPRINTF) || defined(BROKEN_SNPRINTF) +#define snprintf uim_snprintf +int snprintf(char *str, size_t size, const char *format, ...); +#endif + +#ifndef HAVE_STRTONUM +#define strtonum uim_strtonum +long long strtonum(const char *numstr, long long minval, long long maxval, const char **errstrp) +#endif #ifdef __cplusplus } diff -rN -u old-uim/replace/strtonum.c new-uim/replace/strtonum.c --- old-uim/replace/strtonum.c Thu Jan 1 09:00:00 1970 +++ new-uim/replace/strtonum.c Fri Mar 30 00:58:09 2007 @@ -0,0 +1,72 @@ +/* $OpenBSD: strtonum.c,v 1.6 2004/08/03 19:38:01 millert Exp $ */ + +/* + * Copyright (c) 2004 Ted Unangst and Todd Miller + * All rights reserved. + * + * Permission to use, copy, modify, and distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + +/* OPENBSD ORIGINAL: lib/libc/stdlib/strtonum.c */ + +#include + +#ifndef HAVE_STRTONUM +#include +#include +#include + +#define INVALID 1 +#define TOOSMALL 2 +#define TOOLARGE 3 + +long long +strtonum(const char *numstr, long long minval, long long maxval, + const char **errstrp) +{ + long long ll = 0; + char *ep; + int error = 0; + struct errval { + const char *errstr; + int err; + } ev[4] = { + { NULL, 0 }, + { "invalid", EINVAL }, + { "too small", ERANGE }, + { "too large", ERANGE }, + }; + + ev[0].err = errno; + errno = 0; + if (minval > maxval) + error = INVALID; + else { + ll = strtoll(numstr, &ep, 10); + if (numstr == ep || *ep != '\0') + error = INVALID; + else if ((ll == LLONG_MIN && errno == ERANGE) || ll < minval) + error = TOOSMALL; + else if ((ll == LLONG_MAX && errno == ERANGE) || ll > maxval) + error = TOOLARGE; + } + if (errstrp != NULL) + *errstrp = ev[error].errstr; + errno = ev[error].err; + if (error) + ll = 0; + + return (ll); +} + +#endif /* HAVE_STRTONUM */ diff -rN -u old-uim/xim/util.cpp new-uim/xim/util.cpp --- old-uim/xim/util.cpp Fri Mar 30 00:58:09 2007 +++ new-uim/xim/util.cpp Fri Mar 30 00:58:09 2007 @@ -81,778 +81,3 @@ } } -/* - * Copyright for dopr(), fmtstr(), fmtint(), fmtfp(), dopr_outch(), - * abs_val(), POW10(), ROUND(), my_modf(), vsnprintf(), vasprintf(), - * and asprintf() is denoted below. - * - * Copyright Patrick Powell 1995 - * This code is based on code written by Patrick Powell (papowell@astart.com) - * It may be used for any purpose as long as this notice remains intact - * on all source code distributions - */ -/************************************************************** - * Original: - * Patrick Powell Tue Apr 11 09:48:21 PDT 1995 - * A bombproof version of doprnt (dopr) included. - * Sigh. This sort of thing is always nasty do deal with. Note that - * the version here does not include floating point... - * - * snprintf() is used instead of sprintf() as it does limit checks - * for string length. This covers a nasty loophole. - * - * The other functions are there to prevent NULL pointers from - * causing nast effects. - * - * More Recently: - * Brandon Long 9/15/96 for mutt 0.43 - * This was ugly. It is still ugly. I opted out of floating point - * numbers, but the formatter understands just about everything - * from the normal C string format, at least as far as I can tell from - * the Solaris 2.5 printf(3S) man page. - * - * Brandon Long 10/22/97 for mutt 0.87.1 - * Ok, added some minimal floating point support, which means this - * probably requires libm on most operating systems. Don't yet - * support the exponent (e,E) and sigfig (g,G). Also, fmtint() - * was pretty badly broken, it just wasn't being exercised in ways - * which showed it, so that's been fixed. Also, formated the code - * to mutt conventions, and removed dead code left over from the - * original. Also, there is now a builtin-test, just compile with: - * gcc -DTEST_SNPRINTF -o snprintf snprintf.c -lm - * and run snprintf for results. - * - * Thomas Roessler 01/27/98 for mutt 0.89i - * The PGP code was using unsigned hexadecimal formats. - * Unfortunately, unsigned formats simply didn't work. - * - * Michael Elkins 03/05/98 for mutt 0.90.8 - * The original code assumed that both snprintf() and vsnprintf() were - * missing. Some systems only have snprintf() but not vsnprintf(), so - * the code is now broken down under HAVE_SNPRINTF and HAVE_VSNPRINTF. - * - * Andrew Tridgell (tridge@samba.org) Oct 1998 - * fixed handling of %.0f - * added test for HAVE_LONG_DOUBLE - * - * tridge@samba.org, idra@samba.org, April 2001 - * got rid of fcvt code (twas buggy and made testing harder) - * added C99 semantics - * - * Paul Green (paulg@samba.org) April 9, 2003 - * fixed handling of %f when converting fractions with leading zeros. - * (e.g., 0.025). - * - **************************************************************/ - -#if defined(HAVE_VSNPRINTF) && defined(HAVE_C99_VSNPRINTF) -// nothing -#else - -#ifdef HAVE_LONG_DOUBLE -#define LDOUBLE long double -#else -#define LDOUBLE double -#endif - -#ifdef HAVE_LONG_LONG -#define LLONG long long -#else -#define LLONG long -#endif - -static size_t dopr(char *buffer, size_t maxlen, const char *format, - va_list args); -static void fmtstr(char *buffer, size_t *currlen, size_t maxlen, - char *value, int flags, int min, int max); -static void fmtint(char *buffer, size_t *currlen, size_t maxlen, - long value, int base, int min, int max, int flags); -static void fmtfp(char *buffer, size_t *currlen, size_t maxlen, - LDOUBLE fvalue, int min, int max, int flags); -static void dopr_outch(char *buffer, size_t *currlen, size_t maxlen, char c); - -/* - * dopr(): poor man's version of doprintf - */ - -/* format read states */ -#define DP_S_DEFAULT 0 -#define DP_S_FLAGS 1 -#define DP_S_MIN 2 -#define DP_S_DOT 3 -#define DP_S_MAX 4 -#define DP_S_MOD 5 -#define DP_S_CONV 6 -#define DP_S_DONE 7 - -/* format flags - Bits */ -#define DP_F_MINUS (1 << 0) -#define DP_F_PLUS (1 << 1) -#define DP_F_SPACE (1 << 2) -#define DP_F_NUM (1 << 3) -#define DP_F_ZERO (1 << 4) -#define DP_F_UP (1 << 5) -#define DP_F_UNSIGNED (1 << 6) - -/* Conversion Flags */ -#define DP_C_SHORT 1 -#define DP_C_LONG 2 -#define DP_C_LDOUBLE 3 -#define DP_C_LLONG 4 - -#define char_to_int(p) ((p)- '0') -#ifndef MAX -#define MAX(p,q) (((p) >= (q)) ? (p) : (q)) -#endif - -static size_t dopr(char *buffer, size_t maxlen, const char *format, va_list args) -{ - char ch; - LLONG value; - LDOUBLE fvalue; - char *strvalue; - int min; - int max; - int state; - int flags; - int cflags; - size_t currlen; - - state = DP_S_DEFAULT; - currlen = flags = cflags = min = 0; - max = -1; - ch = *format++; - - while (state != DP_S_DONE) { - if (ch == '\0') - state = DP_S_DONE; - - switch (state) { - case DP_S_DEFAULT: - if (ch == '%') - state = DP_S_FLAGS; - else - dopr_outch (buffer, &currlen, maxlen, ch); - ch = *format++; - break; - case DP_S_FLAGS: - switch (ch) { - case '-': - flags |= DP_F_MINUS; - ch = *format++; - break; - case '+': - flags |= DP_F_PLUS; - ch = *format++; - break; - case ' ': - flags |= DP_F_SPACE; - ch = *format++; - break; - case '#': - flags |= DP_F_NUM; - ch = *format++; - break; - case '0': - flags |= DP_F_ZERO; - ch = *format++; - break; - default: - state = DP_S_MIN; - break; - } - break; - case DP_S_MIN: - if (isdigit((unsigned char)ch)) { - min = 10*min + char_to_int (ch); - ch = *format++; - } else if (ch == '*') { - min = va_arg (args, int); - ch = *format++; - state = DP_S_DOT; - } else { - state = DP_S_DOT; - } - break; - case DP_S_DOT: - if (ch == '.') { - state = DP_S_MAX; - ch = *format++; - } else { - state = DP_S_MOD; - } - break; - case DP_S_MAX: - if (isdigit((unsigned char)ch)) { - if (max < 0) - max = 0; - max = 10*max + char_to_int (ch); - ch = *format++; - } else if (ch == '*') { - max = va_arg (args, int); - ch = *format++; - state = DP_S_MOD; - } else { - state = DP_S_MOD; - } - break; - case DP_S_MOD: - switch (ch) { - case 'h': - cflags = DP_C_SHORT; - ch = *format++; - break; - case 'l': - cflags = DP_C_LONG; - ch = *format++; - if (ch == 'l') { /* It's a long long */ - cflags = DP_C_LLONG; - ch = *format++; - } - break; - case 'L': - cflags = DP_C_LDOUBLE; - ch = *format++; - break; - default: - break; - } - state = DP_S_CONV; - break; - case DP_S_CONV: - switch (ch) { - case 'd': - case 'i': - if (cflags == DP_C_SHORT) - value = va_arg (args, int); - else if (cflags == DP_C_LONG) - value = va_arg (args, long int); - else if (cflags == DP_C_LLONG) - value = va_arg (args, LLONG); - else - value = va_arg (args, int); - fmtint (buffer, &currlen, maxlen, value, 10, min, max, flags); - break; - case 'o': - flags |= DP_F_UNSIGNED; - if (cflags == DP_C_SHORT) - value = va_arg (args, unsigned int); - else if (cflags == DP_C_LONG) - value = (long)va_arg (args, unsigned long int); - else if (cflags == DP_C_LLONG) - value = (long)va_arg (args, unsigned LLONG); - else - value = (long)va_arg (args, unsigned int); - fmtint (buffer, &currlen, maxlen, value, 8, min, max, flags); - break; - case 'u': - flags |= DP_F_UNSIGNED; - if (cflags == DP_C_SHORT) - value = va_arg (args, unsigned int); - else if (cflags == DP_C_LONG) - value = (long)va_arg (args, unsigned long int); - else if (cflags == DP_C_LLONG) - value = (LLONG)va_arg (args, unsigned LLONG); - else - value = (long)va_arg (args, unsigned int); - fmtint (buffer, &currlen, maxlen, value, 10, min, max, flags); - break; - case 'X': - flags |= DP_F_UP; - case 'x': - flags |= DP_F_UNSIGNED; - if (cflags == DP_C_SHORT) - value = va_arg (args, unsigned int); - else if (cflags == DP_C_LONG) - value = (long)va_arg (args, unsigned long int); - else if (cflags == DP_C_LLONG) - value = (LLONG)va_arg (args, unsigned LLONG); - else - value = (long)va_arg (args, unsigned int); - fmtint (buffer, &currlen, maxlen, value, 16, min, max, flags); - break; - case 'f': - if (cflags == DP_C_LDOUBLE) - fvalue = va_arg (args, LDOUBLE); - else - fvalue = va_arg (args, double); - /* um, floating point? */ - fmtfp (buffer, &currlen, maxlen, fvalue, min, max, flags); - break; - case 'E': - flags |= DP_F_UP; - case 'e': - if (cflags == DP_C_LDOUBLE) - fvalue = va_arg (args, LDOUBLE); - else - fvalue = va_arg (args, double); - break; - case 'G': - flags |= DP_F_UP; - case 'g': - if (cflags == DP_C_LDOUBLE) - fvalue = va_arg (args, LDOUBLE); - else - fvalue = va_arg (args, double); - break; - case 'c': - dopr_outch (buffer, &currlen, maxlen, va_arg (args, int)); - break; - case 's': - strvalue = va_arg (args, char *); - if (max == -1) { - max = strlen(strvalue); - } - if (min > 0 && max >= 0 && min > max) max = min; - fmtstr (buffer, &currlen, maxlen, strvalue, flags, min, max); - break; - case 'p': - strvalue = (char *)va_arg (args, void *); - fmtint (buffer, &currlen, maxlen, (long) strvalue, 16, min, max, flags); - break; - case 'n': - if (cflags == DP_C_SHORT) { - short int *num; - num = va_arg (args, short int *); - *num = currlen; - } else if (cflags == DP_C_LONG) { - long int *num; - num = va_arg (args, long int *); - *num = (long int)currlen; - } else if (cflags == DP_C_LLONG) { - LLONG *num; - num = va_arg (args, LLONG *); - *num = (LLONG)currlen; - } else { - int *num; - num = va_arg (args, int *); - *num = currlen; - } - break; - case '%': - dopr_outch (buffer, &currlen, maxlen, ch); - break; - case 'w': - /* not supported yet, treat as next char */ - ch = *format++; - break; - default: - /* Unknown, skip */ - break; - } - ch = *format++; - state = DP_S_DEFAULT; - flags = cflags = min = 0; - max = -1; - break; - case DP_S_DONE: - break; - default: - /* hmm? */ - break; /* some picky compilers need this */ - } - } - if (maxlen != 0) { - if (currlen < maxlen - 1) - buffer[currlen] = '\0'; - else if (maxlen > 0) - buffer[maxlen - 1] = '\0'; - } - - return currlen; -} - -static void fmtstr(char *buffer, size_t *currlen, size_t maxlen, - char *value, int flags, int min, int max) -{ - int padlen, strln; /* amount to pad */ - int cnt = 0; - -#ifdef DEBUG_SNPRINTF - printf("fmtstr min=%d max=%d s=[%s]\n", min, max, value); -#endif - if (value == 0) { - value = (char *)""; - } - - for (strln = 0; value[strln]; ++strln); /* strlen */ - padlen = min - strln; - if (padlen < 0) - padlen = 0; - if (flags & DP_F_MINUS) - padlen = -padlen; /* Left Justify */ - - while ((padlen > 0) && (cnt < max)) { - dopr_outch (buffer, currlen, maxlen, ' '); - --padlen; - ++cnt; - } - while (*value && (cnt < max)) { - dopr_outch (buffer, currlen, maxlen, *value++); - ++cnt; - } - while ((padlen < 0) && (cnt < max)) { - dopr_outch (buffer, currlen, maxlen, ' '); - ++padlen; - ++cnt; - } -} - -/* Have to handle DP_F_NUM (ie 0x and 0 alternates) */ - -static void fmtint(char *buffer, size_t *currlen, size_t maxlen, - long value, int base, int min, int max, int flags) -{ - int signvalue = 0; - unsigned long uvalue; - char convert[20]; - int place = 0; - int spadlen = 0; /* amount to space pad */ - int zpadlen = 0; /* amount to zero pad */ - int caps = 0; - - if (max < 0) - max = 0; - - uvalue = value; - - if (!(flags & DP_F_UNSIGNED)) { - if ( value < 0 ) { - signvalue = '-'; - uvalue = -value; - } else { - if (flags & DP_F_PLUS) /* Do a sign (+/i) */ - signvalue = '+'; - else if (flags & DP_F_SPACE) - signvalue = ' '; - } - } - - if (flags & DP_F_UP) caps = 1; /* Should characters be upper case? */ - - do { - convert[place++] = - (caps? "0123456789ABCDEF":"0123456789abcdef") - [uvalue % (unsigned)base ]; - uvalue = (uvalue / (unsigned)base ); - } while (uvalue && (place < 20)); - if (place == 20) place--; - convert[place] = 0; - - zpadlen = max - place; - spadlen = min - MAX (max, place) - (signvalue ? 1 : 0); - if (zpadlen < 0) zpadlen = 0; - if (spadlen < 0) spadlen = 0; - if (flags & DP_F_ZERO) { - zpadlen = MAX(zpadlen, spadlen); - spadlen = 0; - } - if (flags & DP_F_MINUS) - spadlen = -spadlen; /* Left Justifty */ - -#ifdef DEBUG_SNPRINTF - printf("zpad: %d, spad: %d, min: %d, max: %d, place: %d\n", - zpadlen, spadlen, min, max, place); -#endif - - /* Spaces */ - while (spadlen > 0) { - dopr_outch (buffer, currlen, maxlen, ' '); - --spadlen; - } - - /* Sign */ - if (signvalue) - dopr_outch (buffer, currlen, maxlen, signvalue); - - /* Zeros */ - if (zpadlen > 0) { - while (zpadlen > 0) { - dopr_outch (buffer, currlen, maxlen, '0'); - --zpadlen; - } - } - - /* Digits */ - while (place > 0) - dopr_outch (buffer, currlen, maxlen, convert[--place]); - - /* Left Justified spaces */ - while (spadlen < 0) { - dopr_outch (buffer, currlen, maxlen, ' '); - ++spadlen; - } -} - -static LDOUBLE abs_val(LDOUBLE value) -{ - LDOUBLE result = value; - - if (value < 0) - result = -value; - - return result; -} - -static LDOUBLE POW10(int exp) -{ - LDOUBLE result = 1; - - while (exp) { - result *= 10; - exp--; - } - - return result; -} - -static LLONG ROUND(LDOUBLE value) -{ - LLONG intpart; - - intpart = (LLONG)value; - value = value - intpart; - if (value >= 0.5) intpart++; - - return intpart; -} - -/* a replacement for modf that doesn't need the math library. Should - be portable, but slow */ -static double my_modf(double x0, double *iptr) -{ - int i; - long l; - double x = x0; - double f = 1.0; - - for (i = 0; i < 100; i++) { - l = (long)x; - if (l <= (x+1) && l >= (x-1)) break; - x *= 0.1; - f *= 10.0; - } - - if (i == 100) { - /* yikes! the number is beyond what we can handle. What do we do? */ - (*iptr) = 0; - return 0; - } - - if (i != 0) { - double i2; - double ret; - - ret = my_modf(x0-l*f, &i2); - (*iptr) = l*f + i2; - return ret; - } - - (*iptr) = l; - return x - (*iptr); -} - - -static void fmtfp (char *buffer, size_t *currlen, size_t maxlen, - LDOUBLE fvalue, int min, int max, int flags) -{ - int signvalue = 0; - double ufvalue; - char iconvert[311]; - char fconvert[311]; - int iplace = 0; - int fplace = 0; - int padlen = 0; /* amount to pad */ - int zpadlen = 0; - int caps = 0; - int index; - double intpart; - double fracpart; - double temp; - - /* - * AIX manpage says the default is 0, but Solaris says the default - * is 6, and sprintf on AIX defaults to 6 - */ - if (max < 0) - max = 6; - - ufvalue = abs_val (fvalue); - - if (fvalue < 0) { - signvalue = '-'; - } else { - if (flags & DP_F_PLUS) { /* Do a sign (+/i) */ - signvalue = '+'; - } else { - if (flags & DP_F_SPACE) - signvalue = ' '; - } - } - -#if 0 - if (flags & DP_F_UP) caps = 1; /* Should characters be upper case? */ -#endif - -#if 0 - if (max == 0) ufvalue += 0.5; /* if max = 0 we must round */ -#endif - - /* - * Sorry, we only support 16 digits past the decimal because of our - * conversion method - */ - if (max > 16) - max = 16; - - /* We "cheat" by converting the fractional part to integer by - * multiplying by a factor of 10 - */ - - temp = ufvalue; - my_modf(temp, &intpart); - - fracpart = ROUND((POW10(max)) * (ufvalue - intpart)); - - if (fracpart >= POW10(max)) { - intpart++; - fracpart -= POW10(max); - } - - - /* Convert integer part */ - do { - temp = intpart; - my_modf(intpart*0.1, &intpart); - temp = temp*0.1; - index = (int) ((temp -intpart +0.05)* 10.0); - /* index = (int) (((double)(temp*0.1) -intpart +0.05) *10.0); */ - /* printf ("%llf, %f, %x\n", temp, intpart, index); */ - iconvert[iplace++] = - (caps? "0123456789ABCDEF":"0123456789abcdef")[index]; - } while (intpart && (iplace < 311)); - if (iplace == 311) iplace--; - iconvert[iplace] = 0; - - /* Convert fractional part */ - if (fracpart) - { - do { - temp = fracpart; - my_modf(fracpart*0.1, &fracpart); - temp = temp*0.1; - index = (int) ((temp -fracpart +0.05)* 10.0); - /* index = (int) ((((temp/10) -fracpart) +0.05) *10); */ - /* printf ("%lf, %lf, %ld\n", temp, fracpart, index); */ - fconvert[fplace++] = - (caps? "0123456789ABCDEF":"0123456789abcdef")[index]; - } while (fracpart && (fplace < 311)); - if (fplace == 311) fplace--; - } - fconvert[fplace] = 0; - - /* -1 for decimal point, another -1 if we are printing a sign */ - padlen = min - iplace - max - 1 - ((signvalue) ? 1 : 0); - zpadlen = max - fplace; - if (zpadlen < 0) zpadlen = 0; - if (padlen < 0) - padlen = 0; - if (flags & DP_F_MINUS) - padlen = -padlen; /* Left Justifty */ - - if ((flags & DP_F_ZERO) && (padlen > 0)) { - if (signvalue) { - dopr_outch (buffer, currlen, maxlen, signvalue); - --padlen; - signvalue = 0; - } - while (padlen > 0) { - dopr_outch (buffer, currlen, maxlen, '0'); - --padlen; - } - } - while (padlen > 0) { - dopr_outch (buffer, currlen, maxlen, ' '); - --padlen; - } - if (signvalue) - dopr_outch (buffer, currlen, maxlen, signvalue); - - while (iplace > 0) - dopr_outch (buffer, currlen, maxlen, iconvert[--iplace]); - -#ifdef DEBUG_SNPRINTF - printf("fmtfp: fplace=%d zpadlen=%d\n", fplace, zpadlen); -#endif - - /* - * Decimal point. This should probably use locale to find the correct - * char to print out. - */ - if (max > 0) { - dopr_outch (buffer, currlen, maxlen, '.'); - - while (zpadlen > 0) { - dopr_outch (buffer, currlen, maxlen, '0'); - --zpadlen; - } - - while (fplace > 0) - dopr_outch (buffer, currlen, maxlen, fconvert[--fplace]); - } - - while (padlen < 0) { - dopr_outch (buffer, currlen, maxlen, ' '); - ++padlen; - } -} - -static void dopr_outch(char *buffer, size_t *currlen, size_t maxlen, char c) -{ - if (*currlen < maxlen) { - buffer[(*currlen)] = c; - } - (*currlen)++; -} - -#if !defined(HAVE_VSNPRINTF) || !defined(HAVE_C99_VSNPRINTF) -#define vsnprintf uim_vsnprintf -int vsnprintf(char *str, size_t count, const char *fmt, va_list args) -{ - return dopr(str, count, fmt, args); -} -#endif - -#endif - -#ifndef HAVE_VASPRINTF -int vasprintf(char **ret, const char *fmt, va_list ap) -{ - int len; - - len = vsnprintf(NULL, 0, fmt, ap); - if (len <= 0) - return len; - - (*ret) = (char *)malloc(len + 1); - if (*ret == NULL) - return -1; - len = vsnprintf(*ret, len + 1, fmt, ap); - - return len; -} -#endif - -#ifndef HAVE_ASPRINTF -int asprintf(char **ret, const char *fmt, ...) -{ - int len; - va_list ap; - - va_start(ap, fmt); - len = vasprintf(ret, fmt, ap); - va_end(ap); - - return len; -} -#endif