diff options
-rw-r--r-- | .cvsignore | 7 | ||||
-rw-r--r-- | Makefile.am | 15 | ||||
-rw-r--r-- | README | 28 | ||||
-rw-r--r-- | acconfig.h | 10 | ||||
-rw-r--r-- | acinclude.m4 | 249 | ||||
-rwxr-xr-x | autogen.sh | 43 | ||||
-rw-r--r-- | configure.in | 221 | ||||
-rw-r--r-- | debug.c | 36 | ||||
-rw-r--r-- | libast-config.in | 42 | ||||
-rw-r--r-- | libast.h | 383 | ||||
-rw-r--r-- | libast.spec.in | 42 | ||||
-rw-r--r-- | libast_internal.h | 68 | ||||
-rw-r--r-- | mem.c | 450 | ||||
-rw-r--r-- | msgs.c | 81 | ||||
-rw-r--r-- | snprintf.c | 521 | ||||
-rw-r--r-- | strings.c | 549 |
16 files changed, 2745 insertions, 0 deletions
diff --git a/.cvsignore b/.cvsignore new file mode 100644 index 0000000..81ac941 --- /dev/null +++ b/.cvsignore @@ -0,0 +1,7 @@ +Makefile +Makefile.in +.deps +.libs +lib*.la +*.da +*.lo diff --git a/Makefile.am b/Makefile.am new file mode 100644 index 0000000..3b10484 --- /dev/null +++ b/Makefile.am @@ -0,0 +1,15 @@ +# $Id$ + +AUTOMAKE_OPTIONS = foreign + +bin_SCRIPTS = libast-config +lib_LTLIBRARIES = libast.la +include_HEADERS = libast.h + +libast_la_SOURCES = debug.c mem.c msgs.c strings.c snprintf.c libast.h libast_internal.h + +LIBS = -lm + +libast_la_LDFLAGS = -version-info 1:0:0 + +EXTRA_DIST = README @@ -0,0 +1,28 @@ +LibAST README +------------- + +LibAST is the Library of Assorted Spiffy Things. It contains many +spiffy things, and it is a library. Thus, the ever-so-creative name. +LibAST has been previously known as libmej, the Eterm helper library +which nobody really understood and certainly never used. My current +plan is to gradually remove some of the neat stuff from Eterm that +could be made generic (things like the theme parsing engine, the +command-line options parser, perhaps the event engine, ...) and place +it here in the hopes that others will find them useful. + +Building LibAST +--------------- + +From the top of the source tree, type each of the following and hit +Enter after each: + + ./configure + make + +Installing LibAST +----------------- + +After performing the build step above, run: + + make install + diff --git a/acconfig.h b/acconfig.h new file mode 100644 index 0000000..ce3a432 --- /dev/null +++ b/acconfig.h @@ -0,0 +1,10 @@ +#undef LIBAST_VERSION +#undef WITH_DMALLOC +#undef HAVE_SNPRINTF_BUG +#undef DEBUG +#undef CONFIG_SEARCH_PATH +#undef AUTHORS +#undef CONFIG_BUFF +#undef LIBAST_X11_SUPPORT +#undef LIBAST_IMLIB2_SUPPORT +#undef LIBAST_MMX_SUPPORT diff --git a/acinclude.m4 b/acinclude.m4 new file mode 100644 index 0000000..f1436c9 --- /dev/null +++ b/acinclude.m4 @@ -0,0 +1,249 @@ +dnl acl.m4 -- Written by Duncan Simpson <dps@io.stargate.co.uk> +dnl Posted to BUGTRAQ on 17 June 1999 +dnl Used by encouragement. :-) + +dnl Check snprintf for overrun potential +AC_DEFUN(dps_snprintf_oflow, +[AC_MSG_CHECKING(whether snprintf ignores n) +AC_CACHE_VAL(dps_cv_snprintf_bug, +[AC_TRY_RUN( +changequote(<<, >>)dnl +<<#include <stdio.h> + +#ifndef HAVE_SNPRINTF +#ifdef HAVE_VSNPRINTF +#include "vsnprintf.h" +#else /* not HAVE_VSNPRINTF */ +#include "vsnprintf.c" +#endif /* HAVE_VSNPRINTF */ +#endif /* HAVE_SNPRINTF */ + +int main(void) +{ +char ovbuf[7]; +int i; +for (i=0; i<7; i++) ovbuf[i]='x'; +snprintf(ovbuf, 4,"foo%s", "bar"); +if (ovbuf[5]!='x') exit(1); +snprintf(ovbuf, 4,"foo%d", 666); +if (ovbuf[5]!='x') exit(1); +exit(0); +} >> +changequote([, ]), dps_cv_snprintf_bug=0, dps_cv_snprintf_bug=1, +dps_cv_snprintf_bug=2)]) +if test $dps_cv_snprintf_bug -eq 0; then + AC_MSG_RESULT([no, snprintf is ok]) +else if test $dps_cv_snprint_bug -eq 1; then + AC_MSG_RESULT([yes, snprintf is broken]) + AC_DEFINE(HAVE_SNPRINTF_BUG,1) +else + AC_MSG_RESULT([unknown, assuming yes]) + AC_DEFINE(HAVE_SNPRINTF_BUG,1) +fi; fi]) + +dnl Check vsnprintf for overrun potential +AC_DEFUN(dps_vsnprintf_oflow, +[AC_MSG_CHECKING(whether vsnprintf ignores n) +AC_CACHE_VAL(dps_cv_vsnprintf_bug, +[AC_TRY_RUN( +changequote(<<, >>)dnl +<<#include <stdio.h> +#include <stdarg.h> + +#ifndef HAVE_VSNPRINTF +#include "vsnprintf.c" +#endif /* HAVE_VSNPRINTF */ + +int prnt(char *s, const char *fmt, ...) +{ + va_list argp; + va_start(argp, fmt); + vsnprintf(s, 4, fmt, argp); + va_end(argp); +} + +int main(void) +{ + char ovbuf[7]; + int i; + for (i=0; i<7; i++) ovbuf[i]='x'; + prnt(ovbuf, "foo%s", "bar"); + if (ovbuf[5]!='x') exit(1); + prnt(ovbuf, "foo%d", 666); + if (ovbuf[5]!='x') exit(1); + exit(0); +} >> +changequote([, ]), dps_cv_vsnprintf_bug=0, dps_cv_vsnprintf_bug=1, +dps_cv_vsnprintf_bug=2)]) + +if test $dps_cv_vsnprintf_bug -eq 0; then + AC_MSG_RESULT([no, vsnprintf is ok]) +else if test $dps_cv_vsnprint_bug -eq 1; then + AC_MSG_RESULT([yes, vsnprintf is broken]) + AC_DEFINE(HAVE_VSNPRINTF_BUG,1) +else + AC_MSG_RESULT([unknown, assuming yes]) + AC_DEFINE(HAVE_VSNPRINTF_BUG,1) +fi; fi]) + +dnl open and symlink interaction bug test +AC_DEFUN(dps_symlink_open_bug, +[AC_MSG_CHECKING(security of interaction between symlink and open) +AC_CACHE_VAL(dps_cv_symlink_open_bug, +[mkdir conftest.d +AC_TRY_RUN( +changequote(<<, >>)dnl +<<#include <stdio.h> +#ifdef HAVE_STDLIB_H +#include <stdlib.h> +#endif +#ifdef HAVE_SYS_TYPES_H +#include <sys/types.h> +#endif +#ifdef HAVE_SYS_STAT_H +#include <sys/stat.h> +#endif +#ifdef HAVE_FCNTL_H +#include <fcntl.h> +#endif +#ifdef HAVE_UNISTD_H +#include <unistd.h> +#endif +#ifdef HAVE_ERRNO_H +#include <errno.h> +#else +extern int errno; +#endif + +int main(void) +{ + int fd; + if (chdir("conftest.d")!=0) + exit(1); + if (symlink("foo","bar")!=0) + exit(1); + if ((fd=open("bar", O_CREAT | O_EXCL | O_WRONLY, 0700))==0) + { + write(fd, "If the symlink was to .rhosts you would be unhappy", 50); + close(fd); + exit(1); + } + if (errno!=EEXIST) + exit(1); + exit(0); +} >> +changequote([, ]), cps_cv_symlink_open_bug=0, +[if test -r conftest.d/foo; then + cps_cv_symlink_open_bug=2 +else + cps_cv_symlink_open_bug=1 +fi], cps_cv_symlink_open_buf=3) +rm -rf conftest.d]) +case "$cps_cv_symlink_open_bug" in +0) AC_MSG_RESULT(secure) ;; +1) AC_MSG_RESULT(errno wrong but ok) + AC_DEFINE(HAVE_SYMLINK_OPEN_ERRNO_BUG) ;; +2) AC_MSG_RESULT(insecure) + AC_DEFINE(HAVE_SYMLINK_OPEN_SECURITY_HOLE) + AC_DEFINE(HAVE_SYMLINK_OPEN_ERRNO_BUG) ;; +3) AC_MSG_RESULT(assuming insecure) + AC_DEFINE(HAVE_SYMLINK_OPEN_SECURITY_HOLE) + AC_DEFINE(HAVE_SYMLINK_OPEN_ERRNO_BUG) ;; +*) AC_MSG_RESULT($cps_cv_symlink_open_bug) + AC_MSG_ERROR(Impossible value of cps_cv_symlink_open_bug) ;; +esac]) + +dnl Check to RLIMIT_NPROC resource limit +AC_DEFUN(dps_rlimit_nproc, +[AC_MSG_CHECKING(for working RLIMIT_NPROC resource limit) +AC_CACHE_VAL(dps_cv_rlimit_nproc, +[AC_TRY_RUN( +changequote(<<, >>)dnl +<< +#ifndef HAVE_STDLIB_H +#include <stdlib.h> +#endif /* HAVE_STDLIB_H */ +#ifndef HAVE_SIGNAL_H +#include <signal.h> +#endif /* HAVE_SIGNAL_H */ +#ifdef HAVE_UNISTD_H +#include <unistd.h> +#endif /* HAVE_UNISTD_H */ +#ifdef HAVE_SYS_RESOURCE_H +#include <sys/resource.h> +#endif /* HAVE_SYS_RESOURCE_H */ + +int main(void) +{ +#ifdef RLIMIT_NPROC + static const struct rlimit pid_lim={RLIMIT_NPROC, 1}; + pid_t f; + + signal(SIGCHLD, SIG_IGN); + setrlimit(RLIMIT_NPROC, (struct rlimit *) &pid_lim); + if ((f=fork())==0) + exit(0); + if (f==-1) + exit(0); /* The fork() failed (the right thing) */ +#endif + exit(1); +} >> +changequote([, ]), cps_cv_rlimit_nproc=0, cps_cv_rlimit_nproc=1, +cps_cv_rlimit_nproc=2)]) +if test $cps_cv_rlimit_nproc -eq 0; then + AC_MSG_RESULT([yes]) + AC_DEFINE(HAVE_RLIMIT_NPROC,1) +else if test $cps_cv_rlimit_nproc -eq 1; then + AC_MSG_RESULT([no]) +else + AC_MSG_RESULT([unknown, assuming none]) +fi; fi]) + +dnl Check to RLIMIT_MEMLOCK resource limit +AC_DEFUN(cps_rlimit_memlock, +[AC_MSG_CHECKING(for RLIMIT_MEMLOCK resource limit) +AC_CACHE_VAL(cps_cv_rlimit_memlock, +[AC_TRY_RUN( +changequote(<<, >>)dnl +<< +#ifndef HAVE_STDLIB_H +#include <stdlib.h> +#endif /* HAVE_STDLIB_H */ +#ifndef HAVE_SIGNAL_H +#include <signal.h> +#endif /* HAVE_SIGNAL_H */ +#ifdef HAVE_UNISTD_H +#include <unistd.h> +#endif /* HAVE_UNISTD_H */ +#ifdef HAVE_SYS_RESOURCE_H +#include <sys/resource.h> +#endif /* HAVE_SYS_RESOURCE_H */ +#ifdef HAVE_SYS_MMAN +#include <sys/mman.h> +#endif /* HAVE_SYS_MMAN */ +#ifdef HAVE_ERRNO_H +#include <errno.h> +#endif /* HAVE_ERRNO_H */ + +int main(void) +{ +#ifdef RLIMIT_MEMLOCK + static const struct rlimit mlock_lim={RLIMIT_MEMLOCK, 0}; + void *memory; + + if (setrlimit(RLIMIT_MEMLOCK, (struct rlimit *) &mlock_lim)!=-1) + exit(0); +#endif +exit(1); +} >> +changequote([, ]), cps_cv_rlimit_memlock=0, cps_cv_rlimit_memlock=1, +cps_cv_rlimit_memlock=2)]) +if test $cps_cv_rlimit_memlock -eq 0; then + AC_MSG_RESULT([yes]) + AC_DEFINE(HAVE_RLIMIT_MEMLOCK,1) +else if test $cps_cv_rlimit_memlock -eq 1; then + AC_MSG_RESULT([no]) +else + AC_MSG_RESULT([unknown, assuming none]) +fi; fi]) + diff --git a/autogen.sh b/autogen.sh new file mode 100755 index 0000000..aca00dd --- /dev/null +++ b/autogen.sh @@ -0,0 +1,43 @@ +#!/bin/sh +# Run this to generate all the initial makefiles, etc. +# $Id$ + +DIE=0 + +echo "Generating configuration files for libast, please wait...." + +(autoconf --version) < /dev/null > /dev/null 2>&1 || { + echo + echo "You must have autoconf installed to compile libast." + echo "Download the appropriate package for your distribution," + echo "or get the source tarball at ftp://ftp.gnu.org/pub/gnu/" + DIE=1 +} + +(libtool --version) < /dev/null > /dev/null 2>&1 || { + echo + echo "You must have libtool installed to compile libast." + echo "Download the appropriate package for your distribution," + echo "or get the source tarball at ftp://ftp.gnu.org/pub/gnu/" + DIE=1 +} + +(automake --version) < /dev/null > /dev/null 2>&1 || { + echo + echo "You must have automake installed to compile libast." + echo "Download the appropriate package for your distribution," + echo "or get the source tarball at ftp://ftp.gnu.org/pub/gnu/" + DIE=1 +} + +if test "$DIE" -eq 1; then + exit 1 +fi + +(set -x && libtoolize -c -f) +(set -x && aclocal -I . $ACLOCAL_FLAGS) +(set -x && autoheader) +(set -x && automake -a -c) +(set -x && autoconf) + +./configure "$@" diff --git a/configure.in b/configure.in new file mode 100644 index 0000000..23ec363 --- /dev/null +++ b/configure.in @@ -0,0 +1,221 @@ +dnl# $Id$ + +AC_INIT(configure.in) +AM_INIT_AUTOMAKE(libast, 0.1) +AC_DEFINE_UNQUOTED(LIBAST_VERSION, "$VERSION") + +dnl# Set some basic variables +AUTHORS="Michael Jennings (mej@eterm.org)" +AC_SUBST(AUTHORS) +AC_DEFINE_UNQUOTED(AUTHORS, "$AUTHORS") + +AC_PROG_CC +AC_PROG_CPP + +dnl# These must be run after AC_PROG_CC but before any other macros that use +dnl# the C compiler +AC_AIX +AC_ISC_POSIX +AC_MINIX + +dnl# At least make the attempt to support CygWin32 +AC_CYGWIN +AC_ARG_PROGRAM + +AM_PROG_LIBTOOL + +AC_GCC_TRADITIONAL + +AC_PROG_INSTALL + +dnl# Check for host system type +AC_CANONICAL_HOST + +dnl# Check the sanity of what we've done so far +AM_SANITY_CHECK + +dnl# Most people don't want the developer-only clutter +AM_MAINTAINER_MODE + +dnl# If it's there, what the hell? +AM_WITH_DMALLOC + +dnl# Look for needed programs +AC_CHECK_PROG(SED, sed, sed, false) +AC_CHECK_PROG(RM, rm, rm, true) +AC_CHECK_PROG(CP, cp, cp, false) +AC_CHECK_PROG(CHMOD, chmod, chmod, true) +AC_CHECK_PROG(TAR, tar, tar, tar) +AC_CHECK_PROG(MKDIR, mkdir, mkdir, false) +AC_CHECK_PROG(CTAGS, ctags, ctags, true) +AC_CHECK_PROG(AR, ar, ar, false) +AC_CHECK_PROG(MV, mv, mv, true) +AC_LN_S + +AC_CHECK_SIZEOF(char, 1) +AC_CHECK_SIZEOF(short, 4) +AC_CHECK_SIZEOF(int, 4) +AC_CHECK_SIZEOF(long, 4) +AC_CHECK_SIZEOF(void *, 4) +AC_CHECK_SIZEOF(long long, 8) +AC_C_BIGENDIAN + +AC_C_CONST +AC_C_INLINE +AC_PATH_XTRA + +if test ! -z "$X_CFLAGS"; then + if test -z "$CPPFLAGS"; then + CPPFLAGS="$X_CFLAGS" + else + CPPFLAGS="$CPPFLAGS $X_CFLAGS" + fi +fi +if test ! -z "$X_LIBS"; then + if test -z "$LDFLAGS"; then + LDFLAGS="$X_LIBS" + else + LDFLAGS="$LDFLAGS $X_LIBS" + fi +fi + +dnl# +dnl# X LIBRARIES +dnl# +LIBAST_X11_SUPPORT="" +if test "x$no_x" != "xyes"; then + AC_CHECK_LIB(X11, XOpenDisplay, LIBAST_X11_SUPPORT="X11" ; AC_DEFINE(LIBAST_X11_SUPPORT)) +fi +AC_SUBST(LIBAST_X11_SUPPORT) + +dnl# Checks for header files. +AC_HEADER_SYS_WAIT +AC_CHECK_HEADERS(fcntl.h termios.h sys/ioctl.h sys/select.h sys/time.h sys/sockio.h sys/byteorder.h malloc.h \ +utmpx.h unistd.h bsd/signal.h regex.h regexp.h stdarg.h) +AC_HEADER_TIME + +dnl# Missing typedefs and replacements +AC_TYPE_MODE_T +AC_CHECK_TYPE(off_t, long) +AC_TYPE_PID_T +AC_TYPE_UID_T + +dnl# Checks for library functions. +AC_TYPE_SIGNAL +AC_CHECK_FUNCS(memmove putenv strsep memmem usleep snprintf strcasestr strcasechr strcasepbrk strrev) +dps_snprintf_oflow() + +dnl# Did they want debugging? +AC_MSG_CHECKING(for debugging level) +AC_ARG_WITH(debugging, [ --with-debugging[=num] compile in debugging support. num >= 0], + if test "$withval" = "yes"; then + withval=4 + else + : + fi + if test "$withval" != "no"; then + AC_MSG_RESULT($withval) + AC_DEFINE_UNQUOTED(DEBUG, $withval) + else + AC_MSG_RESULT(no, disabling all debugging support) + AC_DEFINE_UNQUOTED(DEBUG, 0) + AC_WARN(*** Debugging support disabled. Client programs will ***) + AC_WARN(*** not have access to any libast debugging routines! ***) + fi, AC_MSG_RESULT(4) + AC_DEFINE_UNQUOTED(DEBUG, 4) +) + +AC_ARG_WITH(imlib, +[ --with-imlib[=DIR] compile with Imlib support (Imlib residing in DIR/lib) (default)], + if test "$withval" != "no"; then + if test "$withval" != "yes"; then + CPPFLAGS="$CPPFLAGS -I${withval}/include" + LDFLAGS="$LDFLAGS -L${withval}/lib" + fi + USE_IMLIB=1 + else + USE_IMLIB=0 + fi, USE_IMLIB=1 +) +LIBAST_IMLIB2_SUPPORT="" +if test $USE_IMLIB -eq 1 ; then + AC_CHECK_LIB(dl, dlopen, GRLIBS="-ldl", , $GRLIBS) + AC_CHECK_LIB(ttf, TT_Init_FreeType, GRLIBS="-lttf $GRLIBS", , $GRLIBS) + AC_CHECK_LIB(Imlib2, imlib_create_image, + GRLIBS="-lImlib2 $GRLIBS" + AC_DEFINE(LIBAST_IMLIB2_SUPPORT) + LIBAST_IMLIB2_SUPPORT="Imlib2" + , + AC_WARN(*** Imlib2 support has been disabled because Imlib2 ***) + AC_WARN(*** was not found or could not be linked. ***) + , $GRLIBS) +fi +AC_SUBST(LIBAST_IMLIB2_SUPPORT) + +AC_MSG_CHECKING(for MMX support) +HAVE_MMX="" +AC_ARG_ENABLE(mmx, [ --enable-mmx enable MMX assembly routines], + test x$enableval = xyes && HAVE_MMX="yes" + , + if test x$build_os = xlinux-gnu; then + grep mmx /proc/cpuinfo >/dev/null 2>&1 && HAVE_MMX="yes" + fi + ) +LIBAST_MMX_SUPPORT="" +if test -n "$HAVE_MMX"; then + AC_MSG_RESULT(yes) + AC_DEFINE(LIBAST_MMX_SUPPORT) + LIBAST_MMX_SUPPORT="MMX" +else + AC_MSG_RESULT(no) +fi +AC_SUBST(LIBAST_MMX_SUPPORT) + +CONFIG_BUFF_SIZE=20480 +AC_MSG_CHECKING(for the buffer size of the config file parser) +AC_ARG_WITH(config-buffer-size, +[ --with-config-buffer-size + specifies the size of the buffer Eterm uses for parsing the config file (default is 20 Kb)], + if test "$withval" != "yes" -a "$withval" != "no"; then + CONFIG_BUFF_SIZE=$withval + fi) +AC_MSG_RESULT($CONFIG_BUFF_SIZE bytes) +AC_DEFINE_UNQUOTED(CONFIG_BUFF, $CONFIG_BUFF_SIZE) + +CPPFLAGS=`eval eval eval eval eval echo "-I$includedir -I$prefix/include $CPPFLAGS"` +CPPFLAGS=`echo $CPPFLAGS | tr ' ' '\n' | uniq | grep -v NONE | tr '\n' ' '` +CFLAGS=${CFLAGS--O} +LDFLAGS=`eval eval eval eval eval echo "-L$libdir -L$prefix/lib ${LDFLAGS--O}"` +LDFLAGS=`echo $LDFLAGS | tr ' ' '\n' | uniq | grep -v NONE | tr '\n' ' '` +LIBS="$GRLIBS $X_PRE_LIBS $LIBS $X_EXTRA_LIBS" + +AC_SUBST(CC) +AC_SUBST(CFLAGS) +AC_SUBST(CPPFLAGS) +AC_SUBST(LDFLAGS) +AC_SUBST(LIBS) +AC_SUBST(THREADLIBS) + +basedir=. + +AM_CONFIG_HEADER(config.h) + +AC_OUTPUT(Makefile libast-config libast.spec) +test -f libast-config && chmod 755 libast-config + +echo " +$PACKAGE $VERSION +Configuration: +-------------- + + Source code location: $srcdir + Host System Type: $host + Preprocessor: $CC $CPPFLAGS + Compiler: $CC $CFLAGS + Linker: $CC $LDFLAGS $LIBS + Install path: $prefix + + See src/feature.h for further configuration information. + + Now type 'make' to build $PACKAGE $VERSION. +" @@ -0,0 +1,36 @@ +/* + * Copyright (C) 1997-2000, Michael Jennings + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to + * deal in the Software without restriction, including without limitation the + * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or + * sell copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies of the Software, its documentation and marketing & publicity + * materials, and acknowledgment shall be given in the documentation, materials + * and software packages that this Software was used. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * THE AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER + * IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + */ + +static const char cvs_ident[] = "$Id$"; + +#ifdef HAVE_CONFIG_H +# include <config.h> +#endif + +#include "libast_internal.h" + +/* FIXME: Change this to an unsigned short once the + options parser can handle function pointers. */ +unsigned int libast_debug_level = 0; +unsigned long libast_debug_flags = 0; + diff --git a/libast-config.in b/libast-config.in new file mode 100644 index 0000000..9c9d027 --- /dev/null +++ b/libast-config.in @@ -0,0 +1,42 @@ +#!/bin/sh +# +# libast-config -- libast configuration helper script +# +# 29 October 2000 +# Michael Jennings <mej@eterm.org> +# +# See libast source/documentation for license +# + +prefix=@prefix@ +exec_prefix=@exec_prefix@ +CPPFLAGS="@CPPFLAGS@" +LDFLAGS="@LDFLAGS@" +X11_SUPPORT=@LIBAST_X11_SUPPORT@ +IMLIB2_SUPPORT=@LIBAST_IMLIB2_SUPPORT@ +MMX_SUPPORT=@LIBAST_MMX_SUPPORT@ +VERSION=@VERSION@ + +case $1 in + -h | --help | -help) + echo "Usage: libast-config [--version] [--prefix] [--exec-prefix] [--cppflags] [--ldflags]" + ;; + -v | --version | -version) + echo "Libary of Assorted Spiffy Things: libast $VERSION" + ;; + -p | --prefix | -prefix) + echo "$prefix" + ;; + -e | --exec-prefix | -exec-prefix) + echo "$exec_prefix" + ;; + -c | --cppflags | -cppflags | --cflags | -cflags) + echo "$CPPFLAGS" + ;; + -l | --ldflags | -ldflags | --libs | -libs) + echo "$LDFLAGS" + ;; + -s | --support | -support) + echo "$MMX_SUPPORT $X11_SUPPORT $IMLIB2_SUPPORT" + ;; +esac diff --git a/libast.h b/libast.h new file mode 100644 index 0000000..6620238 --- /dev/null +++ b/libast.h @@ -0,0 +1,383 @@ +/* + * Copyright (C) 1997-2000, Michael Jennings + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to + * deal in the Software without restriction, including without limitation the + * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or + * sell copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies of the Software, its documentation and marketing & publicity + * materials, and acknowledgment shall be given in the documentation, materials + * and software packages that this Software was used. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * THE AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER + * IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + */ + +#ifndef _LIBAST_H_ +#define _LIBAST_H_ + +/* This GNU goop has to go before the system headers */ +#ifdef __GNUC__ +# ifndef __USE_GNU +# define __USE_GNU +# endif +# ifndef _GNU_SOURCE +# define _GNU_SOURCE +# endif +# ifndef _BSD_SOURCE +# define _BSD_SOURCE +# endif +# ifndef inline +# define inline __inline__ +# endif +#endif + +#include <stdio.h> +#include <stdlib.h> +#include <time.h> +#include <sys/types.h> +#include <unistd.h> +#include <ctype.h> +#include <string.h> +#include <errno.h> +#include <signal.h> +#ifdef WITH_DMALLOC +# include <dmalloc.h> +#elif defined(HAVE_MALLOC_H) +# include <malloc.h> +#endif + +#ifdef LIBAST_X11_SUPPORT +# include <X11/Xatom.h> +# include <X11/X.h> +# include <X11/Intrinsic.h> +# ifdef LIBAST_IMLIB2_SUPPORT +# include <Imlib2.h> +# endif +#endif + +/******************************* GENERIC GOOP *********************************/ +#ifndef TRUE +# define TRUE ((unsigned char)(1)) +# define FALSE ((unsigned char)(0)) +#endif + + + +/****************************** DEBUGGING GOOP ********************************/ +#ifndef LIBAST_DEBUG_FD +# define LIBAST_DEBUG_FD (stderr) +#endif +#ifndef DEBUG +# define DEBUG 0 +#endif + +#define DEBUG_LEVEL (libast_debug_level) +#define DEBUG_FLAGS (libast_debug_flags) + +/* A NOP. Does nothing. */ +#define NOP ((void)0) + +/* A macro and an #define to FIXME-ize individual calls or entire code blocks. */ +#define FIXME_NOP(x) +#define FIXME_BLOCK 0 + +/* An "unused block" marker similar to the above. */ +#define UNUSED_BLOCK 0 + +/* The basic debugging output leader. */ +#if defined(__FILE__) && defined(__LINE__) +# ifdef __GNUC__ +# define __DEBUG() fprintf(LIBAST_DEBUG_FD, "[%lu] %12s | %4d: %s(): ", (unsigned long) time(NULL), __FILE__, __LINE__, __FUNCTION__) +# else +# define __DEBUG() fprintf(LIBAST_DEBUG_FD, "[%lu] %12s | %4d: ", (unsigned long) time(NULL), __FILE__, __LINE__) +# endif +#else +# define __DEBUG() NOP +#endif + +/* A quick and dirty macro to say, "Hi! I got here without crashing!" */ +#define MOO() do {__DEBUG(); libast_dprintf("Moo.\n");} while (0) + +/* Assertion/abort macros which are quite a bit more useful than assert() and abort(). */ +#if DEBUG >= 1 +# if defined(__FILE__) && defined(__LINE__) +# ifdef __GNUC__ +# define ASSERT(x) do {if (!(x)) {if (DEBUG_LEVEL>=1) {fatal_error("ASSERT failed in %s() at %s:%d: %s", __FUNCTION__, __FILE__, __LINE__, #x);} \ + else {print_warning("ASSERT failed in %s() at %s:%d: %s", __FUNCTION__, __FILE__, __LINE__, #x);}}} while (0) +# define ASSERT_RVAL(x, val) do {if (!(x)) {if (DEBUG_LEVEL>=1) {fatal_error("ASSERT failed in %s() at %s:%d: %s", __FUNCTION__, __FILE__, __LINE__, #x);} \ + else {print_warning("ASSERT failed in %s() at %s:%d: %s", __FUNCTION__, __FILE__, __LINE__, #x);} \ + return (val);}} while (0) +# define ASSERT_NOTREACHED() do {if (DEBUG_LEVEL>=1) {fatal_error("ASSERT failed in %s() at %s:%d: This code should not be reached.", __FUNCTION__, __FILE__, __LINE__);} \ + else {print_warning("ASSERT failed in %s() at %s:%d: This code should not be reached.", __FUNCTION__, __FILE__, __LINE__);} \ + } while (0) +# define ASSERT_NOTREACHED_RVAL(val) do {if (DEBUG_LEVEL>=1) {fatal_error("ASSERT failed in %s() at %s:%d: This code should not be reached.", __FUNCTION__, __FILE__, __LINE__);} \ + else {print_warning("ASSERT failed in %s() at %s:%d: This code should not be reached.", __FUNCTION__, __FILE__, __LINE__);} \ + return (val);} while (0) +# define ABORT() fatal_error("Aborting in %s() at %s:%d.", __FUNCTION__, __FILE__, __LINE__) +# else +# define ASSERT(x) do {if (!(x)) {if (DEBUG_LEVEL>=1) {fatal_error("ASSERT failed at %s:%d: %s", __FILE__, __LINE__, #x);} \ + else {print_warning("ASSERT failed at %s:%d: %s", __FILE__, __LINE__, #x);}}} while (0) +# define ASSERT_RVAL(x, val) do {if (!(x)) {if (DEBUG_LEVEL>=1) {fatal_error("ASSERT failed at %s:%d: %s", __FILE__, __LINE__, #x);} \ + else {print_warning("ASSERT failed at %s:%d: %s", __FILE__, __LINE__, #x);} \ + return (val);}} while (0) +# define ASSERT_NOTREACHED() do {if (DEBUG_LEVEL>=1) {fatal_error("ASSERT failed at %s:%d: This code should not be reached.", __FILE__, __LINE__);} \ + else {print_warning("ASSERT failed at %s:%d: This code should not be reached.", __FILE__, __LINE__);} \ + } while (0) +# define ASSERT_NOTREACHED_RVAL(val) do {if (DEBUG_LEVEL>=1) {fatal_error("ASSERT failed at %s:%d: This code should not be reached.", __FILE__, __LINE__);} \ + else {print_warning("ASSERT failed at %s:%d: This code should not be reached.", __FILE__, __LINE__);} \ + return (val);} while (0) +# define ABORT() fatal_error("Aborting at %s:%d.", __FILE__, __LINE__) +# endif +# else +# define ASSERT(x) do {if (!(x)) {if (DEBUG_LEVEL>=1) {fatal_error("ASSERT failed: %s", #x);} \ + else {print_warning("ASSERT failed: %s", #x);}}} while (0) +# define ASSERT_RVAL(x, val) do {if (!(x)) {if (DEBUG_LEVEL>=1) {fatal_error("ASSERT failed: %s", #x);} \ + else {print_warning("ASSERT failed: %s", #x);} return (val);}} while (0) +# define ASSERT_NOTREACHED() return +# define ASSERT_NOTREACHED_RVAL(x) return (x) +# define ABORT() fatal_error("Aborting.\n") +# endif +# define REQUIRE(x) do {if (!(x)) {if (DEBUG_LEVEL>=1) {__DEBUG(); libast_dprintf("REQUIRE failed: %s\n", #x);} return;}} while (0) +# define REQUIRE_RVAL(x, v) do {if (!(x)) {if (DEBUG_LEVEL>=1) {__DEBUG(); libast_dprintf("REQUIRE failed: %s\n", #x);} return (v);}} while (0) +#else +# define ASSERT(x) NOP +# define ASSERT_RVAL(x, val) NOP +# define ASSERT_NOTREACHED() return +# define ASSERT_NOTREACHED_RVAL(val) return (val) +# define ABORT() fatal_error("Aborting.\n") +# define REQUIRE(x) do {if (!(x)) return;} while (0) +# define REQUIRE_RVAL(x, v) do {if (!(x)) return (v);} while (0) +#endif + +#define NONULL(x) ((x) ? (x) : ("<null>")) + +/* Macros for printing debugging messages */ +#if DEBUG >= 1 +# ifndef DPRINTF +# define DPRINTF(x) do { __DEBUG(); libast_dprintf x; } while (0) +# endif +# define DPRINTF1(x) do { if (DEBUG_LEVEL >= 1) {__DEBUG(); libast_dprintf x;} } while (0) +# define DPRINTF2(x) do { if (DEBUG_LEVEL >= 2) {__DEBUG(); libast_dprintf x;} } while (0) +# define DPRINTF3(x) do { if (DEBUG_LEVEL >= 3) {__DEBUG(); libast_dprintf x;} } while (0) +# define DPRINTF4(x) do { if (DEBUG_LEVEL >= 4) {__DEBUG(); libast_dprintf x;} } while (0) +# define DPRINTF5(x) do { if (DEBUG_LEVEL >= 5) {__DEBUG(); libast_dprintf x;} } while (0) +# define DPRINTF6(x) do { if (DEBUG_LEVEL >= 6) {__DEBUG(); libast_dprintf x;} } while (0) +# define DPRINTF7(x) do { if (DEBUG_LEVEL >= 7) {__DEBUG(); libast_dprintf x;} } while (0) +# define DPRINTF8(x) do { if (DEBUG_LEVEL >= 8) {__DEBUG(); libast_dprintf x;} } while (0) +# define DPRINTF9(x) do { if (DEBUG_LEVEL >= 9) {__DEBUG(); libast_dprintf x;} } while (0) +#else +# ifndef DPRINTF +# define DPRINTF(x) NOP +# endif +# define DPRINTF1(x) NOP +# define DPRINTF2(x) NOP +# define DPRINTF3(x) NOP +# define DPRINTF4(x) NOP +# define DPRINTF5(x) NOP +# define DPRINTF6(x) NOP +# define DPRINTF7(x) NOP +# define DPRINTF8(x) NOP +# define DPRINTF9(x) NOP +#endif + +/* Use this for stuff that you only want turned on in dire situations */ +#define D_NEVER(x) NOP + +#define DEBUG_MEM 5 +#define D_MEM(x) DPRINTF5(x) +#define DEBUG_STRINGS 9999 +#define D_STRINGS(x) D_NEVER(x) + + + +/********************************* MEM GOOP ***********************************/ +#if (DEBUG >= DEBUG_MEM) +# define MALLOC(sz) libast_malloc(__FILE__, __LINE__, (sz)) +# define CALLOC(type,n) libast_calloc(__FILE__, __LINE__, (n), (sizeof(type))) +# define REALLOC(mem,sz) libast_realloc(#mem, __FILE__, __LINE__, (mem), (sz)) +# define FREE(ptr) do { libast_free(#ptr, __FILE__, __LINE__, (ptr)); (ptr) = NULL; } while (0) +# define STRDUP(s) libast_strdup(#s, __FILE__, __LINE__, (s)) +# define MALLOC_DUMP() libast_dump_mem_tables() +# define X_CREATE_PIXMAP(d, win, w, h, depth) libast_x_create_pixmap(__FILE__, __LINE__, (d), (win), (w), (h), (depth)) +# define X_FREE_PIXMAP(d, p) libast_x_free_pixmap(#p, __FILE__, __LINE__, (d), (p)) +# ifdef HAVE_LIBIMLIB2 +# define IMLIB_REGISTER_PIXMAP(p) libast_imlib_register_pixmap(#p, __FILE__, __LINE__, (p)) +# define IMLIB_FREE_PIXMAP(p) libast_imlib_free_pixmap(#p, __FILE__, __LINE__, (p)) +# else +# define IMLIB_REGISTER_PIXMAP(p) NOP +# define IMLIB_FREE_PIXMAP(p) NOP +# endif +# define PIXMAP_DUMP() libast_dump_pixmap_tables() +# define X_CREATE_GC(d, win, f, gcv) libast_x_create_gc(__FILE__, __LINE__, (d), (win), (f), (gcv)) +# define X_FREE_GC(d, gc) libast_x_free_gc(#gc, __FILE__, __LINE__, (d), (gc)) +# define GC_DUMP() libast_dump_gc_tables() +# define MALLOC_MOD 25 +# define REALLOC_MOD 25 +# define CALLOC_MOD 25 +# define FREE_MOD 25 +#else +# define MALLOC(sz) malloc(sz) +# define CALLOC(type,n) calloc((n),(sizeof(type))) +# define REALLOC(mem,sz) ((sz) ? ((mem) ? (realloc((mem), (sz))) : (malloc(sz))) : ((mem) ? (free(mem), NULL) : (NULL))) +# define FREE(ptr) do { free(ptr); (ptr) = NULL; } while (0) +# define STRDUP(s) strdup(s) +# define MALLOC_DUMP() NOP +# define X_CREATE_PIXMAP(d, win, w, h, depth) XCreatePixmap((d), (win), (w), (h), (depth)) +# define X_FREE_PIXMAP(d, p) XFreePixmap((d), (p)) +# ifdef HAVE_LIBIMLIB2 +# define IMLIB_REGISTER_PIXMAP(p) NOP +# define IMLIB_FREE_PIXMAP(p) imlib_free_pixmap_and_mask(p) +# else +# define IMLIB_REGISTER_PIXMAP(p) NOP +# define IMLIB_FREE_PIXMAP(p) NOP +# endif +# define PIXMAP_DUMP() NOP +# define X_CREATE_GC(d, win, f, gcv) XCreateGC((d), (win), (f), (gcv)) +# define X_FREE_GC(d, gc) XFreeGC((d), (gc)) +# define GC_DUMP() NOP +#endif + +/* Fast memset() macro contributed by vendu */ +#if (SIZEOF_LONG == 8) +# define MEMSET_LONG() l |= l<<32 +#else +# define MEMSET_LONG() ((void)0) +#endif + +#define MEMSET(s, c, count) do { \ + char *end = (char *)(s) + (count); \ + long l; \ + long *l_dest = (long *)(s); \ + char *c_dest; \ + \ + /* areas of less than 4 * sizeof(long) are set in 1-byte chunks. */ \ + if (((unsigned long) count) >= 4 * sizeof(long)) { \ + /* fill l with c. */ \ + l = (c) | (c)<<8; \ + l |= l<<16; \ + MEMSET_LONG(); \ + \ + /* fill in 1-byte chunks until boundary of long is reached. */ \ + if ((unsigned long)l_dest & (unsigned long)(sizeof(long) -1)) { \ + c_dest = (char *)l_dest; \ + while ((unsigned long)c_dest & (unsigned long)(sizeof(long) -1)) { \ + *(c_dest++) = (c); \ + } \ + l_dest = (long *)c_dest; \ + } \ + \ + /* fill in long-size chunks as long as possible. */ \ + while (((unsigned long) (end - (char *)l_dest)) >= sizeof(long)) { \ + *(l_dest++) = l; \ + } \ + } \ + \ + /* fill the tail in 1-byte chunks. */ \ + if ((char *)l_dest < end) { \ + c_dest = (char *)l_dest; \ + *(c_dest++) = (c); \ + while (c_dest < end) { \ + *(c_dest++) = (c); \ + } \ + } \ + } while (0) + + + +/******************************* STRINGS GOOP *********************************/ + +#ifdef __GNUC__ +# define SWAP(a, b) __extension__ ({__typeof__(a) tmp = (a); (a) = (b); (b) = tmp;}) +#else +# define SWAP(a, b) do {void *tmp = ((void *)(a)); (a) = (b); (b) = tmp;} while (0) +#endif + +#define CONST_STRLEN(x) (sizeof(x) - 1) +#define BEG_STRCASECMP(s, constr) (strncasecmp(s, constr, CONST_STRLEN(constr))) + + + +/******************************** PROTOTYPES **********************************/ + +/* msgs.c */ +extern int libast_dprintf(const char *, ...); +extern void print_error(const char *fmt, ...); +extern void print_warning(const char *fmt, ...); +extern void fatal_error(const char *fmt, ...); + +/* debug.c */ +extern unsigned int DEBUG_LEVEL; + +/* mem.c */ +extern void memrec_init(void); +extern void *libast_malloc(const char *, unsigned long, size_t); +extern void *libast_realloc(const char *, const char *, unsigned long, void *, size_t); +extern void *libast_calloc(const char *, unsigned long, size_t, size_t); +extern void libast_free(const char *, const char *, unsigned long, void *); +extern char *libast_strdup(const char *, const char *, unsigned long, const char *); +extern void libast_dump_mem_tables(void); +#ifdef LIBAST_X11_SUPPORT +extern Pixmap libast_x_create_pixmap(const char *, unsigned long, Display *, Drawable, unsigned int, unsigned int, unsigned int); +extern void libast_x_free_pixmap(const char *, const char *, unsigned long, Display *, Pixmap); +# ifdef LIBAST_IMLIB2_SUPPORT +extern void libast_imlib_register_pixmap(const char *var, const char *filename, unsigned long line, Pixmap p); +extern void libast_imlib_free_pixmap(const char *var, const char *filename, unsigned long line, Pixmap p); +# endif +extern void libast_dump_pixmap_tables(void); +extern GC libast_x_create_gc(const char *, unsigned long, Display *, Drawable, unsigned long, XGCValues *); +extern void libast_x_free_gc(const char *, const char *, unsigned long, Display *, GC); +extern void libast_dump_gc_tables(void); +#endif + +/* strings.c */ +extern char *left_str(const char *, unsigned long); +extern char *mid_str(const char *, unsigned long, unsigned long); +extern char *right_str(const char *, unsigned long); +extern unsigned char regexp_match(const char *, const char *); +extern char *get_word(unsigned long, const char *); +extern char *get_pword(unsigned long, const char *); +extern unsigned long num_words(const char *); +extern char *strip_whitespace(char *); +extern char *downcase_str(char *); +extern char *upcase_str(char *); +#ifndef HAVE_STRCASESTR +extern char *strcasestr(const char *, const char *); +#endif +#ifndef HAVE_STRCASECHR +extern char *strcasechr(const char *, const char); +#endif +#ifndef HAVE_STRCASEPBRK +extern char *strcasepbrk(const char *, const char *); +#endif +#ifndef HAVE_STRREV +extern char *strrev(char *); +#endif +#if !(HAVE_STRSEP) +extern char *strsep(char **, char *); +#endif +extern char *safe_str(char *, unsigned short); +extern char *garbage_collect(char *, size_t); +extern char *file_garbage_collect(char *, size_t); +extern char *condense_whitespace(char *); +extern void hex_dump(void *, size_t); +#ifndef HAVE_MEMMEM +extern void *memmem(const void *, size_t, const void *, size_t); +#endif +#ifndef HAVE_USLEEP +extern void usleep(unsigned long); +#endif +#ifndef HAVE_SNPRINTF +extern int vsnprintf(char *str, size_t count, const char *fmt, va_list args); +extern int snprintf(char *str, size_t count, const char *fmt, ...); +#endif + +#endif /* _LIBAST_H_ */ diff --git a/libast.spec.in b/libast.spec.in new file mode 100644 index 0000000..48b56a1 --- /dev/null +++ b/libast.spec.in @@ -0,0 +1,42 @@ +Summary: Library of Assorted Spiffy Things +Name: @PACKAGE@ +Version: @VERSION@ +Release: 1 +Copyright: BSD +Group: System Environment/Libraries +Source: %{name}-%{version}.tar.gz +URL: http://www.eterm.org/ +BuildRoot: /var/tmp/%{name}-root +Prefix: %{_prefix} + +%description +LibAST is the Library of Assorted Spiffy Things. It contains various +handy routines and drop-in substitutes for some good-but-non-portable +functions. It currently has a built-in memory tracking subsystem as +well as some debugging aids and other similar tools. + +%changelog + +%prep +%setup -q + +%build +%configure +make + +%install +make DESTDIR=$RPM_BUILD_ROOT install +%post +/sbin/ldconfig + +%postun +/sbin/ldconfig + +%clean +rm -rf $RPM_BUILD_ROOT + +%files +%defattr(-,root,root) +%{_prefix}/bin/* +%{_prefix}/lib/* +%{_prefix}/include/* diff --git a/libast_internal.h b/libast_internal.h new file mode 100644 index 0000000..c8fd26c --- /dev/null +++ b/libast_internal.h @@ -0,0 +1,68 @@ +/* + * Copyright (C) 1997-2000, Michael Jennings + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to + * deal in the Software without restriction, including without limitation the + * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or + * sell copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies of the Software, its documentation and marketing & publicity + * materials, and acknowledgment shall be given in the documentation, materials + * and software packages that this Software was used. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * THE AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER + * IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + */ + +#ifndef _LIBAST_INTERNAL_H_ +#define _LIBAST_INTERNAL_H_ + +/* This GNU goop has to go before the system headers */ +#ifdef __GNUC__ +# ifndef __USE_GNU +# define __USE_GNU +# endif +# ifndef _GNU_SOURCE +# define _GNU_SOURCE +# endif +# ifndef _BSD_SOURCE +# define _BSD_SOURCE +# endif +# ifndef inline +# define inline __inline__ +# endif +#endif + +#include "config.h" +#include "libast.h" + +#ifdef HAVE_REGEX_H +# include <regex.h> +#endif +#ifdef HAVE_STDARG_H +# include <stdarg.h> +#endif + +/********************************* MEM GOOP ***********************************/ +#define LIBAST_FNAME_LEN 20 + +typedef struct ptr_struct { + void *ptr; + size_t size; + char file[LIBAST_FNAME_LEN + 1]; + unsigned long line; +} ptr_t; +typedef struct memrec_struct { + unsigned long cnt; + ptr_t *ptrs; +} memrec_t; + + +#endif /* _LIBAST_INTERNAL_H_ */ @@ -0,0 +1,450 @@ + +/* + * Copyright (C) 1997-2000, Michael Jennings + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to + * deal in the Software without restriction, including without limitation the + * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or + * sell copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies of the Software, its documentation and marketing & publicity + * materials, and acknowledgment shall be given in the documentation, materials + * and software packages that this Software was used. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * THE AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER + * IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + */ + +static const char cvs_ident[] = "$Id$"; + +#ifdef HAVE_CONFIG_H +# include <config.h> +#endif + +#include "libast_internal.h" + +static void memrec_add_var(memrec_t *, const char *, unsigned long, void *, size_t); +static ptr_t *memrec_find_var(memrec_t *, const void *); +static void memrec_rem_var(memrec_t *, const char *, const char *, unsigned long, const void *); +static void memrec_chg_var(memrec_t *, const char *, const char *, unsigned long, const void *, void *, size_t); +static void memrec_dump_pointers(memrec_t *); +static void memrec_dump_resources(memrec_t *); + +/* + * These're added for a pretty obvious reason -- they're implemented towards + * The beginning of each one's respective function. (The ones with capitalized + * letters. I'm not sure that they'll be useful outside of gdb. Maybe. + */ +#ifdef MALLOC_CALL_DEBUG +static int malloc_count = 0; +static int calloc_count = 0; +static int realloc_count = 0; +static int free_count = 0; +#endif + +static memrec_t malloc_rec, pixmap_rec, gc_rec; + +void +memrec_init(void) +{ + D_MEM(("Constructing memory allocation records\n")); + malloc_rec.ptrs = (ptr_t *) malloc(sizeof(ptr_t)); + pixmap_rec.ptrs = (ptr_t *) malloc(sizeof(ptr_t)); + gc_rec.ptrs = (ptr_t *) malloc(sizeof(ptr_t)); +} + +static void +memrec_add_var(memrec_t *memrec, const char *filename, unsigned long line, void *ptr, size_t size) +{ + register ptr_t *p; + + ASSERT(memrec != NULL); + memrec->cnt++; + if ((memrec->ptrs = (ptr_t *) realloc(memrec->ptrs, sizeof(ptr_t) * memrec->cnt)) == NULL) { + D_MEM(("Unable to reallocate pointer list -- %s\n", strerror(errno))); + } + p = memrec->ptrs + memrec->cnt - 1; + D_MEM(("Adding variable (%8p, %lu bytes) from %s:%lu.\n", ptr, size, filename, line)); + D_MEM(("Storing as pointer #%lu at %8p (from %8p).\n", memrec->cnt, p, memrec->ptrs)); + p->ptr = ptr; + p->size = size; + strncpy(p->file, filename, LIBAST_FNAME_LEN); + p->file[LIBAST_FNAME_LEN] = 0; + p->line = line; +} + +static ptr_t * +memrec_find_var(memrec_t *memrec, const void *ptr) +{ + register ptr_t *p; + register unsigned long i; + + ASSERT(memrec != NULL); + REQUIRE_RVAL(ptr != NULL, NULL); + + for (i = 0, p = memrec->ptrs; i < memrec->cnt; i++, p++) { + if (p->ptr == ptr) { + D_MEM(("Found pointer #%lu stored at %8p (from %8p)\n", i + 1, p, memrec->ptrs)); + return p; + } + } + return NULL; +} + +static void +memrec_rem_var(memrec_t *memrec, const char *var, const char *filename, unsigned long line, const void *ptr) +{ + register ptr_t *p; + + ASSERT(memrec != NULL); + + if ((p = memrec_find_var(memrec, ptr)) == NULL) { + D_MEM(("ERROR: File %s, line %d attempted to free variable %s (%8p) which was not allocated with MALLOC/REALLOC\n", filename, line, var, ptr)); + return; + } + memrec->cnt--; + D_MEM(("Removing variable %s (%8p) of size %lu\n", var, ptr, p->size)); + memmove(p, p + 1, sizeof(ptr_t) * (memrec->cnt - (p - memrec->ptrs))); + memrec->ptrs = (ptr_t *) realloc(memrec->ptrs, sizeof(ptr_t) * memrec->cnt); +} + +static void +memrec_chg_var(memrec_t *memrec, const char *var, const char *filename, unsigned long line, const void *oldp, void *newp, size_t size) +{ + register ptr_t *p; + + ASSERT(memrec != NULL); + + if ((p = memrec_find_var(memrec, oldp)) == NULL) { + D_MEM(("ERROR: File %s, line %d attempted to realloc variable %s (%8p) which was not allocated with MALLOC/REALLOC\n", filename, line, var, oldp)); + return; + } + D_MEM(("Changing variable %s (%8p, %lu -> %8p, %lu)\n", var, oldp, p->size, newp, size)); + p->ptr = newp; + p->size = size; + strncpy(p->file, filename, LIBAST_FNAME_LEN); + p->line = line; +} + +static void +memrec_dump_pointers(memrec_t *memrec) +{ + register ptr_t *p; + unsigned long i, j, k, l, total = 0; + unsigned long len; + unsigned char buff[9]; + + ASSERT(memrec != NULL); + fprintf(LIBAST_DEBUG_FD, "PTR: %lu pointers stored.\n", memrec->cnt); + fprintf(LIBAST_DEBUG_FD, "PTR: Pointer | Filename | Line | Address | Size | Offset | 00 01 02 03 04 05 06 07 | ASCII \n"); + fprintf(LIBAST_DEBUG_FD, "PTR: ---------+----------------------+--------+----------+--------+---------+-------------------------+---------\n"); + fflush(LIBAST_DEBUG_FD); + len = sizeof(ptr_t) * memrec->cnt; + memset(buff, 0, sizeof(buff)); + + /* First, dump the contents of the memrec->ptrs[] array. */ + for (p = memrec->ptrs, j = 0; j < len; j += 8) { + fprintf(LIBAST_DEBUG_FD, "PTR: %07lu | %20s | %6lu | %8p | %06lu | %07x | ", (unsigned long) 0, "", (unsigned long) 0, memrec->ptrs, + (unsigned long) (sizeof(ptr_t) * memrec->cnt), (unsigned int) j); + /* l is the number of characters we're going to output */ + l = ((len - j < 8) ? (len - j) : (8)); + /* Copy l bytes (up to 8) from memrec->ptrs[] (p) to buffer */ + memcpy(buff, ((char *) p) + j, l); + buff[l] = 0; + for (k = 0; k < l; k++) { + fprintf(LIBAST_DEBUG_FD, "%02x ", buff[k]); + } + /* If we printed less than 8 bytes worth, pad with 3 spaces per byte */ + for (; k < 8; k++) { + fprintf(LIBAST_DEBUG_FD, " "); + } + /* Finally, print the printable ASCII string for those l bytes */ + fprintf(LIBAST_DEBUG_FD, "| %-8s\n", safe_str((char *) buff, l)); + /* Flush after every line in case we crash */ + fflush(LIBAST_DEBUG_FD); + } + + /* Now print out each pointer and its contents. */ + for (i = 0; i < memrec->cnt; p++, i++) { + /* Add this pointer's size to our total */ + total += p->size; + for (j = 0; j < p->size; j += 8) { + fprintf(LIBAST_DEBUG_FD, "PTR: %07lu | %20s | %6lu | %8p | %06lu | %07x | ", i + 1, NONULL(p->file), p->line, p->ptr, (unsigned long) p->size, (unsigned int) j); + /* l is the number of characters we're going to output */ + l = ((p->size - j < 8) ? (p->size - j) : (8)); + /* Copy l bytes (up to 8) from p->ptr to buffer */ + memcpy(buff, ((char *) p->ptr) + j, l); + buff[l] = 0; + for (k = 0; k < l; k++) { + fprintf(LIBAST_DEBUG_FD, "%02x ", buff[k]); + } + /* If we printed less than 8 bytes worth, pad with 3 spaces per byte */ + for (; k < 8; k++) { + fprintf(LIBAST_DEBUG_FD, " "); + } + /* Finally, print the printable ASCII string for those l bytes */ + fprintf(LIBAST_DEBUG_FD, "| %-8s\n", safe_str((char *) buff, l)); + /* Flush after every line in case we crash */ + fflush(LIBAST_DEBUG_FD); + } + } + fprintf(LIBAST_DEBUG_FD, "PTR: Total allocated memory: %10lu bytes\n", total); + fflush(LIBAST_DEBUG_FD); +} + +static void +memrec_dump_resources(memrec_t *memrec) +{ + register ptr_t *p; + unsigned long i, total; + unsigned long len; + + ASSERT(memrec != NULL); + len = memrec->cnt; + fprintf(LIBAST_DEBUG_FD, "RES: %lu resources stored.\n", memrec->cnt); + fprintf(LIBAST_DEBUG_FD, "RES: Index | Resource ID | Filename | Line | Size \n"); + fprintf(LIBAST_DEBUG_FD, "RES: -------+-------------+----------------------+--------+--------\n"); + fflush(LIBAST_DEBUG_FD); + + for (p = memrec->ptrs, i = 0, total = 0; i < len; i++, p++) { + total += p->size; + fprintf(LIBAST_DEBUG_FD, "RES: %5lu | 0x%08x | %20s | %6lu | %6lu\n", i, (unsigned) p->ptr, NONULL(p->file), p->line, (unsigned long) p->size); + /* Flush after every line in case we crash */ + fflush(LIBAST_DEBUG_FD); + } + fprintf(LIBAST_DEBUG_FD, "RES: Total size: %lu bytes\n", total); + fflush(LIBAST_DEBUG_FD); +} + +/******************** MEMORY ALLOCATION INTERFACE ********************/ +void * +libast_malloc(const char *filename, unsigned long line, size_t size) +{ + void *temp; + +#ifdef MALLOC_CALL_DEBUG + ++malloc_count; + if (!(malloc_count % MALLOC_MOD)) { + fprintf(LIBAST_DEBUG_FD, "Calls to malloc(): %d\n", malloc_count); + } +#endif + + D_MEM(("%lu bytes requested at %s:%lu\n", size, filename, line)); + + temp = (void *) malloc(size); + ASSERT_RVAL(temp != NULL, NULL); + if (DEBUG_LEVEL >= DEBUG_MEM) { + memrec_add_var(&malloc_rec, filename, line, temp, size); + } + return (temp); +} + +void * +libast_realloc(const char *var, const char *filename, unsigned long line, void *ptr, size_t size) +{ + void *temp; + +#ifdef MALLOC_CALL_DEBUG + ++realloc_count; + if (!(realloc_count % REALLOC_MOD)) { + D_MEM(("Calls to realloc(): %d\n", realloc_count)); + } +#endif + + D_MEM(("Variable %s (%8p -> %lu) at %s:%lu\n", var, ptr, (unsigned long) size, filename, line)); + if (ptr == NULL) { + temp = (void *) libast_malloc(__FILE__, __LINE__, size); + } else { + temp = (void *) realloc(ptr, size); + ASSERT_RVAL(temp != NULL, ptr); + if (DEBUG_LEVEL >= DEBUG_MEM) { + memrec_chg_var(&malloc_rec, var, filename, line, ptr, temp, size); + } + } + return (temp); +} + +void * +libast_calloc(const char *filename, unsigned long line, size_t count, size_t size) +{ + void *temp; + +#ifdef MALLOC_CALL_DEBUG + ++calloc_count; + if (!(calloc_count % CALLOC_MOD)) { + fprintf(LIBAST_DEBUG_FD, "Calls to calloc(): %d\n", calloc_count); + } +#endif + + D_MEM(("%lu units of %lu bytes each requested at %s:%lu\n", count, size, filename, line)); + temp = (void *) calloc(count, size); + ASSERT_RVAL(temp != NULL, NULL); + if (DEBUG_LEVEL >= DEBUG_MEM) { + memrec_add_var(&malloc_rec, filename, line, temp, size * count); + } + return (temp); +} + +void +libast_free(const char *var, const char *filename, unsigned long line, void *ptr) +{ +#ifdef MALLOC_CALL_DEBUG + ++free_count; + if (!(free_count % FREE_MOD)) { + fprintf(LIBAST_DEBUG_FD, "Calls to free(): %d\n", free_count); + } +#endif + + D_MEM(("Variable %s (%8p) at %s:%lu\n", var, ptr, filename, line)); + if (ptr) { + if (DEBUG_LEVEL >= DEBUG_MEM) { + memrec_rem_var(&malloc_rec, var, filename, line, ptr); + } + free(ptr); + } else { + D_MEM(("ERROR: Caught attempt to free NULL pointer\n")); + } +} + +char * +libast_strdup(const char *var, const char *filename, unsigned long line, const char *str) +{ + register char *newstr; + register size_t len; + + D_MEM(("Variable %s (%8p) at %s:%lu\n", var, str, filename, line)); + + len = strlen(str) + 1; /* Copy NUL byte also */ + newstr = (char *) libast_malloc(filename, line, len); + strcpy(newstr, str); + return (newstr); +} + +void +libast_dump_mem_tables(void) +{ + fprintf(LIBAST_DEBUG_FD, "Dumping memory allocation table:\n"); + memrec_dump_pointers(&malloc_rec); +} + +#ifdef LIBAST_X11_SUPPORT + +/******************** PIXMAP ALLOCATION INTERFACE ********************/ + +Pixmap +libast_x_create_pixmap(const char *filename, unsigned long line, Display *d, Drawable win, unsigned int w, unsigned int h, unsigned int depth) +{ + Pixmap p; + + D_MEM(("Creating %ux%u pixmap of depth %u for window 0x%08x at %s:%lu\n", w, h, depth, win, filename, line)); + + p = XCreatePixmap(d, win, w, h, depth); + ASSERT_RVAL(p != None, None); + if (DEBUG_LEVEL >= DEBUG_MEM) { + memrec_add_var(&pixmap_rec, filename, line, (void *) p, w * h * (depth / 8)); + } + return (p); +} + +void +libast_x_free_pixmap(const char *var, const char *filename, unsigned long line, Display *d, Pixmap p) +{ + D_MEM(("Freeing pixmap %s (0x%08x) at %s:%lu\n", var, p, filename, line)); + if (p) { + if (DEBUG_LEVEL >= DEBUG_MEM) { + memrec_rem_var(&pixmap_rec, var, filename, line, (void *) p); + } + XFreePixmap(d, p); + } else { + D_MEM(("ERROR: Caught attempt to free NULL pixmap\n")); + } +} + +# ifdef LIBAST_IMLIB2_SUPPORT +void +libast_imlib_register_pixmap(const char *var, const char *filename, unsigned long line, Pixmap p) +{ + D_MEM(("Registering pixmap %s (0x%08x) created by Imlib2 at %s:%lu\n", var, p, filename, line)); + if (p) { + if (DEBUG_LEVEL >= DEBUG_MEM) { + if (!memrec_find_var(&pixmap_rec, (void *) p)) { + memrec_add_var(&pixmap_rec, filename, line, (void *) p, 1); + } else { + D_MEM(("Pixmap 0x%08x already registered.\n")); + } + } + } else { + D_MEM(("ERROR: Refusing to register a NULL pixmap\n")); + } +} + +void +libast_imlib_free_pixmap(const char *var, const char *filename, unsigned long line, Pixmap p) +{ + D_MEM(("Freeing pixmap %s (0x%08x) at %s:%lu using Imlib2\n", var, p, filename, line)); + if (p) { + if (DEBUG_LEVEL >= DEBUG_MEM) { + memrec_rem_var(&pixmap_rec, var, filename, line, (void *) p); + } + imlib_free_pixmap_and_mask(p); + } else { + D_MEM(("ERROR: Caught attempt to free NULL pixmap\n")); + } +} +# endif + +void +libast_dump_pixmap_tables(void) +{ + fprintf(LIBAST_DEBUG_FD, "Dumping X11 Pixmap allocation table:\n"); + memrec_dump_resources(&pixmap_rec); +} + + + +/********************** GC ALLOCATION INTERFACE **********************/ + +GC +libast_x_create_gc(const char *filename, unsigned long line, Display *d, Drawable win, unsigned long mask, XGCValues *gcv) +{ + GC gc; + + D_MEM(("Creating gc for window 0x%08x at %s:%lu\n", win, filename, line)); + + gc = XCreateGC(d, win, mask, gcv); + ASSERT_RVAL(gc != None, None); + if (DEBUG_LEVEL >= DEBUG_MEM) { + memrec_add_var(&gc_rec, filename, line, (void *) gc, sizeof(XGCValues)); + } + return (gc); +} + +void +libast_x_free_gc(const char *var, const char *filename, unsigned long line, Display *d, GC gc) +{ + D_MEM(("libast_x_free_gc() called for variable %s (0x%08x) at %s:%lu\n", var, gc, filename, line)); + if (gc) { + if (DEBUG_LEVEL >= DEBUG_MEM) { + memrec_rem_var(&gc_rec, var, filename, line, (void *) gc); + } + XFreeGC(d, gc); + } else { + D_MEM(("ERROR: Caught attempt to free NULL GC\n")); + } +} + +void +libast_dump_gc_tables(void) +{ + fprintf(LIBAST_DEBUG_FD, "Dumping X11 GC allocation table:\n"); + memrec_dump_resources(&gc_rec); +} + +#endif @@ -0,0 +1,81 @@ +/* + * Copyright (C) 1997-2000, Michael Jennings + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to + * deal in the Software without restriction, including without limitation the + * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or + * sell copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies of the Software, its documentation and marketing & publicity + * materials, and acknowledgment shall be given in the documentation, materials + * and software packages that this Software was used. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * THE AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER + * IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + */ + +static const char cvs_ident[] = "$Id$"; + +#ifdef HAVE_CONFIG_H +# include <config.h> +#endif + +#include "libast_internal.h" + +int +libast_dprintf(const char *format, ...) +{ + va_list args; + int n; + + va_start(args, format); + n = vfprintf(LIBAST_DEBUG_FD, format, args); + va_end(args); + fflush(LIBAST_DEBUG_FD); + return (n); +} + +/* Print a non-terminal error message */ +void +print_error(const char *fmt, ...) +{ + va_list arg_ptr; + + va_start(arg_ptr, fmt); + fprintf(stderr, PACKAGE ": Error: "); + vfprintf(stderr, fmt, arg_ptr); + va_end(arg_ptr); +} + +/* Print a simple warning */ +void +print_warning(const char *fmt, ...) +{ + va_list arg_ptr; + + va_start(arg_ptr, fmt); + fprintf(stderr, PACKAGE ": Warning: "); + vfprintf(stderr, fmt, arg_ptr); + va_end(arg_ptr); +} + +/* Print a fatal error message and terminate */ +void +fatal_error(const char *fmt, ...) +{ + va_list arg_ptr; + + va_start(arg_ptr, fmt); + fprintf(stderr, PACKAGE ": FATAL: "); + vfprintf(stderr, fmt, arg_ptr); + va_end(arg_ptr); + exit(-1); +} + diff --git a/snprintf.c b/snprintf.c new file mode 100644 index 0000000..668f33b --- /dev/null +++ b/snprintf.c @@ -0,0 +1,521 @@ +#ifdef HAVE_CONFIG_H +# include <config.h> +#endif + +#include <errno.h> +#ifdef HAVE_STDARG_H +# include <stdarg.h> +#endif + +static const char cvs_ident[] = "$Id$"; + +/* + * Shamelessly snarfed from Enlightenment... + * which shamelessly snarfed from sane... + * which shamelessly snarfed from LPR + * which probably shamelessly snarfed from.... + * + * Moved comments to end so I can actually read the code.. cleaned out useless + * junk.... + */ + +#if !defined(HAVE_SNPRINTF) || (HAVE_SNPRINTF_BUG == 1) + +#define VA_LOCAL_DECL va_list ap +#define VA_START(f) va_start(ap, f) +#define VA_SHIFT(v,t) ; /* no-op for ANSI */ +#define VA_END va_end(ap) + +/* + * dopr(): poor man's version of doprintf + */ + +static void dopr(char *buffer, const char *format, va_list args); +static void fmtstr(char *value, int ljust, int len, int zpad, int precision); +static void fmtnum(long value, int base, int dosign, + int ljust, int len, int zpad, int precision); +static void fmtdouble(int fmt, double value, + int ljust, int len, int zpad, int precision); +static void dostr(char *); +static char *output; +static void dopr_outch(int c); +static char *end; +int visible_control = 1; + +int +vsnprintf(char *str, size_t count, const char *fmt, va_list args) +{ + str[0] = 0; + end = str + count - 1; + dopr(str, fmt, args); + if (count > 0) { + end[0] = 0; + } + return (strlen(str)); +} + +#ifdef HAVE_STDARG_H +int +snprintf(char *str, size_t count, const char *fmt,...) +#else +int +snprintf(va_alist) + va_dcl + +#endif +{ +#ifndef HAVE_STDARG_H + char *str; + size_t count; + char *fmt; + +#endif + VA_LOCAL_DECL; + + VA_START(fmt); + VA_SHIFT(str, char *); + + VA_SHIFT(count, size_t); + VA_SHIFT(fmt, char *); + + (void) vsnprintf(str, count, fmt, ap); + VA_END; + return (strlen(str)); +} + +static void +dopr(char *buffer, const char *format, va_list args) +{ + int ch; + long value; + int longflag = 0; + char *strvalue; + int ljust; + int len; + int zpad; + int precision; + int set_precision; + double dval; + + output = buffer; + while ((ch = *format++)) { + switch (ch) { + case '%': + ljust = len = zpad = 0; + precision = -1; + set_precision = 0; + nextch: + ch = *format++; + switch (ch) { + case 0: + dostr("**end of format**"); + return; + case '-': + ljust = 1; + goto nextch; + case '.': + set_precision = 1; + precision = 0; + goto nextch; + case '*': + len = va_arg(args, int); + + goto nextch; + case '0': /* set zero padding if len not set */ + if (len == 0 && set_precision == 0) + zpad = '0'; + case '1': + case '2': + case '3': + case '4': + case '5': + case '6': + case '7': + case '8': + case '9': + if (set_precision) { + precision = precision * 10 + ch - '0'; + } else { + len = len * 10 + ch - '0'; + } + goto nextch; + case 'l': + longflag = 1; + goto nextch; + case 'u': + case 'U': + /*fmtnum(value,base,dosign,ljust,len, zpad, precision) */ + if (longflag) { + value = va_arg(args, long); + } else { + value = va_arg(args, int); + } + fmtnum(value, 10, 0, ljust, len, zpad, precision); + break; + case 'o': + case 'O': + /*fmtnum(value,base,dosign,ljust,len, zpad, precision) */ + if (longflag) { + value = va_arg(args, long); + } else { + value = va_arg(args, int); + } + fmtnum(value, 8, 0, ljust, len, zpad, precision); + break; + case 'd': + case 'i': + case 'D': + if (longflag) { + value = va_arg(args, long); + } else { + value = va_arg(args, int); + } + fmtnum(value, 10, 1, ljust, len, zpad, precision); + break; + case 'x': + if (longflag) { + value = va_arg(args, long); + } else { + value = va_arg(args, int); + } + fmtnum(value, 16, 0, ljust, len, zpad, precision); + break; + case 'X': + if (longflag) { + value = va_arg(args, long); + } else { + value = va_arg(args, int); + } + fmtnum(value, -16, 0, ljust, len, zpad, precision); + break; + case 's': + strvalue = va_arg(args, char *); + + fmtstr(strvalue, ljust, len, zpad, precision); + break; + case 'c': + ch = va_arg(args, int); + + { + char b[2]; + int vsb = visible_control; + + b[0] = ch; + b[1] = 0; + visible_control = 0; + fmtstr(b, ljust, len, zpad, precision); + visible_control = vsb; + } + break; + case 'f': + case 'g': + dval = va_arg(args, double); + + fmtdouble(ch, dval, ljust, len, zpad, precision); + break; + case '%': + dopr_outch(ch); + continue; + default: + dostr("???????"); + } + longflag = 0; + break; + default: + dopr_outch(ch); + break; + } + } + *output = 0; +} + +/* + * Format '%[-]len[.precision]s' + * - = left justify (ljust) + * len = minimum length + * precision = numbers of chars in string to use + */ +static void +fmtstr(char *value, int ljust, int len, int zpad, int precision) +{ + int padlen, strlen, i, c; /* amount to pad */ + + zpad = 0; + if (value == 0) { + value = "<NULL>"; + } + if (precision > 0) { + strlen = precision; + } else { + /* cheap strlen so you do not have library call */ + for (strlen = 0; (c = value[strlen]); ++strlen) { + if (visible_control && iscntrl(c) && !isspace(c)) { + ++strlen; + } + } + } + padlen = len - strlen; + if (padlen < 0) + padlen = 0; + if (ljust) + padlen = -padlen; + while (padlen > 0) { + dopr_outch(' '); + --padlen; + } + /* output characters */ + for (i = 0; (c = value[i]); ++i) { + if (visible_control && iscntrl(c) && !isspace(c)) { + dopr_outch('^'); + c = ('@' | (c & 0x1F)); + } + dopr_outch(c); + } + while (padlen < 0) { + dopr_outch(' '); + ++padlen; + } +} + +static void +fmtnum(long value, int base, int dosign, int ljust, + int len, int zpad, int precision) +{ + int signvalue = 0; + unsigned long uvalue; + char convert[20]; + int place = 0; + int padlen = 0; /* amount to pad */ + int caps = 0; + + precision = 0; + /* DEBUGP(("value 0x%x, base %d, dosign %d, ljust %d, len %d, zpad %d\n", + * value, base, dosign, ljust, len, zpad )); */ + uvalue = value; + if (dosign) { + if (value < 0) { + signvalue = '-'; + uvalue = -value; + } + } + if (base < 0) { + caps = 1; + base = -base; + } + do { + convert[place++] = + (caps ? "0123456789ABCDEF" : "0123456789abcdef") + [uvalue % (unsigned) base]; + uvalue = (uvalue / (unsigned) base); + } + while (uvalue); + convert[place] = 0; + padlen = len - place; + if (padlen < 0) + padlen = 0; + if (ljust) + padlen = -padlen; + /* DEBUGP(( "str '%s', place %d, sign %c, padlen %d\n", + * convert,place,signvalue,padlen)); */ + if (zpad && padlen > 0) { + if (signvalue) { + dopr_outch(signvalue); + --padlen; + signvalue = 0; + } + while (padlen > 0) { + dopr_outch(zpad); + --padlen; + } + } + while (padlen > 0) { + dopr_outch(' '); + --padlen; + } + if (signvalue) + dopr_outch(signvalue); + while (place > 0) + dopr_outch(convert[--place]); + while (padlen < 0) { + dopr_outch(' '); + ++padlen; + } +} + +static void +fmtdouble(int fmt, double value, int ljust, int len, int zpad, int precision) +{ + char convert[128]; + char fmtstr[128]; + int l; + + zpad = 0; + if (len == 0) + len = 10; + if (len > (int) sizeof(convert) - 10) { + len = (int) sizeof(convert) - 10; + } + if (precision > (int) sizeof(convert) - 10) { + precision = (int) sizeof(convert) - 10; + } + if (precision > len) + precision = len; + strcpy(fmtstr, "%"); + if (ljust) + strcat(fmtstr, "-"); + if (len) { + sprintf(fmtstr + strlen(fmtstr), "%d", len); + } + if (precision > 0) { + sprintf(fmtstr + strlen(fmtstr), ".%d", precision); + } + l = strlen(fmtstr); + fmtstr[l] = fmt; + fmtstr[l + 1] = 0; + sprintf(convert, fmtstr, value); + dostr(convert); +} + +static void +dostr(char *str) +{ + while (*str) + dopr_outch(*str++); +} + +static void +dopr_outch(int c) +{ + if (end == 0 || output < end) { + *output++ = c; + } +} + +/************************************************************** + * 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... + * + * plp_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. + **************************************************************/ + +/*************************************************************************** + * LPRng - An Extended Print Spooler System + * + * Copyright 1988-1997, Patrick Powell, San Diego, CA + * papowell@sdsu.edu + * See below for conditions of use. + * + *************************************************************************** + * MODULE: snprintf.c + * PURPOSE: LPRng version of printf - absolutely bombproof (hopefully!) + **************************************************************************/ + +/* + * The "Artistic License" + * + * Preamble + * + * The intent of this document is to state the conditions under which a + * Package may be copied, such that the Copyright Holder maintains some + * semblance of artistic control over the development of the package, + * while giving the users of the package the right to use and distribute + * the Package in a more-or-less customary fashion, plus the right to make + * reasonable modifications. + * + * Definitions: + * + * "Package" refers to the collection of files distributed by the + * Copyright Holder, and derivatives of that collection of files + * created through textual modification. + * + * "Standard Version" refers to such a Package if it has not been + * modified, or has been modified in accordance with the wishes + * of the Copyright Holder as specified below. + * + * "Copyright Holder" is whoever is named in the copyright or + * copyrights for the package. + * + * "You" is you, if you are thinking about copying or distributing + * this Package. + * + * "Reasonable copying fee" is whatever you can justify on the + * basis of media cost, duplication charges, time of people involved, + * and so on. (You will not be required to justify it to the + * Copyright Holder, but only to the computing community at large + * as a market that must bear the fee.) + * + * "libast_freely Available" means that no fee is charged for the item + * itself, though there may be fees involved in handling the item. + * It also means that recipients of the item may redistribute it + * under the same conditions they received it. + * + * 1. You may make and give away verbatim copies of the source form of the + * Standard Version of this Package without restriction, provided that you + * duplicate all of the original copyright notices and associated disclaimers. + * + * 2. You may apply bug fixes, portability fixes and other modifications + * derived from the Public Domain or from the Copyright Holder. A Package + * modified in such a way shall still be considered the Standard Version. + * + * 3. You may otherwise modify your copy of this Package in any way, provided + * that you insert a prominent notice in each changed file stating how and + * when you changed that file, and provided that you do at least ONE of the + * following: + * + * a) place your modifications in the Public Domain or otherwise make them + * libast_freely Available, such as by posting said modifications to Usenet or + * an equivalent medium, or placing the modifications on a major archive + * site such as uunet.uu.net, or by allowing the Copyright Holder to include + * your modifications in the Standard Version of the Package. + * + * b) use the modified Package only within your corporation or organization. + * + * c) rename any non-standard executables so the names do not conflict + * with standard executables, which must also be provided, and provide + * a separate manual page for each non-standard executable that clearly + * documents how it differs from the Standard Version. + * + * d) make other distribution arrangements with the Copyright Holder. + * + * 4. You may distribute the programs of this Package in object code or + * executable form, provided that you do at least ONE of the following: + * + * a) distribute a Standard Version of the executables and library files, + * together with instructions (in the manual page or equivalent) on where + * to get the Standard Version. + * + * b) accompany the distribution with the machine-readable source of + * the Package with your modifications. + * + * c) give non-standard executables non-standard names, and clearly + * document the differences in manual pages (or equivalent), together + * with instructions on where to get the Standard Version. + * + * d) make other distribution arrangements with the Copyright Holder. + * + * 5. You may charge a reasonable copying fee for any distribution of this + * Package. You may charge any fee you choose for support of this + * Package. You may not charge a fee for this Package itself. However, + * you may distribute this Package in aggregate with other (possibly + * commercial) programs as part of a larger (possibly commercial) software + * distribution provided that you do not advertise this Package as a + * product of your own. + * + * 6. The name of the Copyright Holder may not be used to endorse or promote + * products derived from this software without specific prior written permission. + * + * 7. THIS PACKAGE IS PROVIDED "AS IS" AND WITHOUT ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED + * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE. + * + * The End + */ + +#endif /* HAVE_SNPRINTF */ diff --git a/strings.c b/strings.c new file mode 100644 index 0000000..d7c2348 --- /dev/null +++ b/strings.c @@ -0,0 +1,549 @@ +/* + * Copyright (C) 1997-2000, Michael Jennings + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to + * deal in the Software without restriction, including without limitation the + * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or + * sell copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies of the Software, its documentation and marketing & publicity + * materials, and acknowledgment shall be given in the documentation, materials + * and software packages that this Software was used. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * THE AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER + * IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + */ + +static const char cvs_ident[] = "$Id$"; + +#ifdef HAVE_CONFIG_H +# include <config.h> +#endif + +#include <libast_internal.h> + +#ifndef HAVE_MEMMEM +/* Find first occurance of bytestring needle of size needlelen in memory region + haystack of size haystacklen */ +void * +memmem(const void *haystack, register size_t haystacklen, const void *needle, register size_t needlelen) +{ + register char *hs = (char *) haystack; + register char *n = (char *) needle; + register unsigned long i; + register size_t len = haystacklen - needlelen; + + for (i = 0; i < len; i++) { + if (!memcmp(hs + i, n, needlelen)) { + return (hs + i); + } + } + return (NULL); +} +#endif + +#ifndef HAVE_USLEEP +void +usleep(unsigned long usec) +{ + struct timeval delay; + + delay.tv_sec = 0; + delay.tv_usec = usec; + select(0, NULL, NULL, NULL, &delay); + +} + +#endif + +/***** Not needed ****** +#ifndef HAVE_NANOSLEEP +__inline__ void +nanosleep(unsigned long nsec) { + usleep(nsec / 1000); +} +#endif +************************/ + +/* Return the leftmost cnt characters of str */ +char * +left_str(const char *str, unsigned long cnt) +{ + char *tmpstr; + + tmpstr = (char *) MALLOC(cnt + 1); + strncpy(tmpstr, str, cnt); + tmpstr[cnt] = 0; + return (tmpstr); +} + +/* Return cnt characters from str, starting at position index (from 0) */ +char * +mid_str(const char *str, unsigned long index, unsigned long cnt) +{ + char *tmpstr; + const char *pstr = str; + + tmpstr = (char *) MALLOC(cnt + 1); + pstr += index; + strncpy(tmpstr, pstr, cnt); + tmpstr[cnt] = 0; + return (tmpstr); +} + +/* Return the rightmost characters of str */ +char * +right_str(const char *str, unsigned long cnt) +{ + char *tmpstr; + const char *pstr = str; + + tmpstr = (char *) MALLOC(cnt + 1); + pstr += strlen(str); + pstr -= cnt; + strcpy(tmpstr, pstr); + return (tmpstr); +} + +/* Returns TRUE if str matches regular expression pattern, FALSE otherwise */ +#if defined(HAVE_REGEX_H) || defined(IRIX) +unsigned char +regexp_match(register const char *str, register const char *pattern) +{ + register regex_t *rexp; + register int result; + char errbuf[256]; + + rexp = (regex_t *) MALLOC(sizeof(regex_t)); + + if ((result = regcomp(rexp, pattern, REG_EXTENDED)) != 0) { + regerror(result, rexp, errbuf, 256); + fprintf(stderr, "Unable to compile regexp %s -- %s.\n", pattern, errbuf); + FREE(rexp); + return (FALSE); + } + + if (((result = regexec(rexp, str, (size_t) 0, (regmatch_t *) NULL, 0)) + != 0) && (result != REG_NOMATCH)) { + regerror(result, rexp, errbuf, 256); + fprintf(stderr, "Error testing input string %s -- %s.\n", str, errbuf); + FREE(rexp); + return (FALSE); + } + FREE(rexp); + return (!result); +} +#endif + +/* Return malloc'd pointer to index-th word in str. "..." counts as 1 word. */ +#define IS_DELIM(c) (delim ? ((c) == delim) : (isspace(c))) + +char * +get_word(unsigned long index, const char *str) +{ + char *tmpstr; + char delim = 0; + register unsigned long i, j, k; + + k = strlen(str) + 1; + if ((tmpstr = (char *) MALLOC(k)) == NULL) { + fprintf(stderr, "get_word(%lu, %s): Unable to allocate memory -- %s.\n", + index, str, strerror(errno)); + return ((char *) NULL); + } + *tmpstr = 0; + for (i = 0, j = 0; j < index && str[i]; j++) { + for (; isspace(str[i]); i++); + switch (str[i]) { + case '\"': + delim = '\"'; + i++; + break; + case '\'': + delim = '\''; + i++; + break; + default: + delim = 0; + } + for (k = 0; str[i] && !IS_DELIM(str[i]);) { + if (str[i] == '\\') { + if (str[i + 1] == '\'' || str[i + 1] == '\"') { + i++; + } + } + tmpstr[k++] = str[i++]; + } + switch (str[i]) { + case '\"': + case '\'': + i++; + break; + } + tmpstr[k] = 0; + } + + if (j != index) { + FREE(tmpstr); + D_STRINGS(("get_word(%lu, %s) returning NULL.\n", index, str)); + return ((char *) NULL); + } else { + tmpstr = (char *) REALLOC(tmpstr, strlen(tmpstr) + 1); + D_STRINGS(("get_word(%lu, %s) returning \"%s\".\n", index, str, tmpstr)); + return (tmpstr); + } +} + +/* Return pointer into str to index-th word in str. "..." counts as 1 word. */ +char * +get_pword(unsigned long index, const char *str) +{ + register const char *tmpstr = str; + register unsigned long j; + + if (!str) + return ((char *) NULL); + for (; isspace(*tmpstr) && *tmpstr; tmpstr++); + for (j = 1; j < index && *tmpstr; j++) { + for (; !isspace(*tmpstr) && *tmpstr; tmpstr++); + for (; isspace(*tmpstr) && *tmpstr; tmpstr++); + } + + if (*tmpstr == '\"' || *tmpstr == '\'') { + tmpstr++; + } + if (*tmpstr == '\0') { + D_STRINGS(("get_pword(%lu, %s) returning NULL.\n", index, str)); + return ((char *) NULL); + } else { + D_STRINGS(("get_pword(%lu, %s) returning \"%s\"\n", index, str, tmpstr)); + return (char *) tmpstr; + } +} + +/* Returns the number of words in str, for use with get_word() and get_pword(). "..." counts as 1 word. */ +unsigned long +num_words(const char *str) +{ + register unsigned long cnt = 0; + char delim = 0; + register unsigned long i; + + for (i = 0; str[i] && IS_DELIM(str[i]); i++); + for (; str[i]; cnt++) { + switch (str[i]) { + case '\"': + delim = '\"'; + i++; + break; + case '\'': + delim = '\''; + i++; + break; + default: + delim = 0; + } + for (; str[i] && !IS_DELIM(str[i]); i++); + switch (str[i]) { + case '\"': + case '\'': + i++; + break; + } + for (; str[i] && isspace(str[i]); i++); + } + + D_STRINGS(("num_words() returning %lu\n", cnt)); + return (cnt); +} + +char * +strip_whitespace(register char *str) +{ + register unsigned long i, j; + + if ((j = strlen(str))) { + for (i = j - 1; isspace(*(str + i)); i--); + str[j = i + 1] = 0; + for (i = 0; isspace(*(str + i)); i++); + j -= i; + memmove(str, str + i, j + 1); + } + return (str); +} + +char * +downcase_str(char *str) +{ + register char *tmp; + + for (tmp = str; *tmp; tmp++) { + *tmp = tolower(*tmp); + } + D_STRINGS(("downcase_str() returning %s\n", str)); + return (str); +} + +char * +upcase_str(char *str) +{ + register char *tmp; + + for (tmp = str; *tmp; tmp++) { + *tmp = toupper(*tmp); + } + D_STRINGS(("upcase_str() returning %s\n", str)); + return (str); +} + +#ifndef HAVE_STRCASESTR +char * +strcasestr(const char *haystack, register const char *needle) +{ + register const char *t; + register size_t len = strlen(needle); + + for (t = haystack; t && *t; t++) { + if (!strncasecmp(t, needle, len)) { + return ((char *) t); + } + } + return (NULL); +} +#endif + +#ifndef HAVE_STRCASECHR +char * +strcasechr(const char *haystack, register const char needle) +{ + register const char *t; + + for (t = haystack; t && *t; t++) { + if (tolower(*t) == tolower(needle)) { + return ((char *) t); + } + } + return (NULL); +} +#endif + +#ifndef HAVE_STRCASEPBRK +char * +strcasepbrk(const char *haystack, register const char *needle) +{ + register const char *t; + + for (t = haystack; t && *t; t++) { + if (strcasechr(needle, *t)) { + return ((char *) t); + } + } + return (NULL); +} +#endif + +#ifndef HAVE_STRREV +char * +strrev(register char *str) +{ + register int i, j; + + i = strlen(str); + for (j = 0, i--; i > j; i--, j++) { + SWAP(str[j], str[i]); + } + return (str); + +} +#endif + +#if !(HAVE_STRSEP) +char * +strsep(char **str, register char *sep) +{ + + register char *s = *str; + char *sptr; + + D_STRINGS(("strsep(%s, %s) called.\n", *str, sep)); + sptr = s; + for (; *s && !strchr(sep, *s); s++); + if (!*s) { + if (s != sptr) { + *str = s; + D_STRINGS(("Reached end of string with token \"%s\" in buffer\n", sptr)); + return (sptr); + } else { + D_STRINGS(("Reached end of string\n")); + return ((char *) NULL); + } + } + *s = 0; + *str = s + 1; + D_STRINGS(("Got token \"%s\", *str == \"%s\"\n", sptr, *str)); + return (sptr); +} +#endif + +char * +garbage_collect(char *buff, size_t len) +{ + + register char *tbuff = buff, *pbuff = buff; + register unsigned long i, j; + + D_STRINGS(("Garbage collecting on %lu bytes at %10.8p\n", len, buff)); + for (i = 0, j = 0; j < len; j++) + if (pbuff[j]) + tbuff[i++] = pbuff[j]; + tbuff[i++] = '\0'; + D_STRINGS(("Garbage collecting gives: \n%s\n", buff)); + return ((char *) REALLOC(buff, sizeof(char) * i)); +} + +char * +file_garbage_collect(char *buff, size_t len) +{ + + register char *tbuff = buff, *pbuff = buff; + char *tmp1, *tmp2; + register unsigned long j; + + D_STRINGS(("File garbage collecting on %lu bytes at %10.8p\n", len, buff)); + for (j = 0; j < len;) { + switch (pbuff[j]) { + case '#': + for (; !strchr("\r\n", pbuff[j]) && j < len; j++) + pbuff[j] = '\0'; /* First null out the line up to the CR and/or LF */ + for (; strchr("\r\n", pbuff[j]) && j < len; j++) + pbuff[j] = '\0'; /* Then null out the CR and/or LF */ + break; + case '\r': + case '\n': + case '\f': + case ' ': + case '\t': + case '\v': + for (; isspace(pbuff[j]) && j < len; j++) + pbuff[j] = '\0'; /* Null out the whitespace */ + break; + default: + /* Find the end of this line and the occurence of the + next mid-line comment. */ + tmp1 = strpbrk(pbuff + j, "\r\n"); + tmp2 = strstr(pbuff + j, " #"); + + /* If either is null, take the non-null one. Otherwise, + take the lesser of the two. */ + if (!tmp1 || !tmp2) { + tbuff = ((tmp1) ? (tmp1) : (tmp2)); + } else { + tbuff = ((tmp1 < tmp2) ? (tmp1) : (tmp2)); + } + + /* Now let j catch up so that pbuff+j = tbuff; i.e., let + pbuff[j] refer to the same character that tbuff does */ + j += tbuff - (pbuff + j); + + /* Finally, change whatever is at pbuff[j] to a newline. + This will accomplish several things at once: + o It will change a \r to a \n if that's what's there + o If it's a \n, it'll stay the same. No biggie. + o If it's a space, it will end the line there and the + next line will begin with a comment, which is handled + above. */ + if (j < len) + pbuff[j++] = '\n'; + + } + } + + /* Change all occurances of a backslash followed by a newline to nulls + and null out all whitespace up to the next non-whitespace character. + This handles support for breaking a string across multiple lines. */ + for (j = 0; j < len; j++) { + if (pbuff[j] == '\\' && pbuff[j + 1] == '\n') { + pbuff[j++] = '\0'; + for (; isspace(pbuff[j]) && j < len; j++) + pbuff[j] = '\0'; /* Null out the whitespace */ + } + } + + /* And the final step, garbage collect the buffer to condense all + those nulls we just put in. */ + return (garbage_collect(buff, len)); +} + +char * +condense_whitespace(char *s) +{ + + register unsigned char gotspc = 0; + register char *pbuff = s, *pbuff2 = s; + + D_STRINGS(("condense_whitespace(%s) called.\n", s)); + for (; *pbuff2; pbuff2++) { + if (isspace(*pbuff2)) { + if (!gotspc) { + *pbuff = ' '; + gotspc = 1; + pbuff++; + } + } else { + *pbuff = *pbuff2; + gotspc = 0; + pbuff++; + } + } + if ((pbuff >= s) && (isspace(*(pbuff - 1)))) + pbuff--; + *pbuff = 0; + D_STRINGS(("condense_whitespace() returning \"%s\".\n", s)); + return (REALLOC(s, strlen(s) + 1)); +} + +char * +safe_str(register char *str, unsigned short len) +{ + register unsigned short i; + + for (i = 0; i < len; i++) { + if (iscntrl(str[i])) { + str[i] = '.'; + } + } + + return (str); +} + +void +hex_dump(void *buff, register size_t count) +{ + + register unsigned long j, k, l; + register unsigned char *ptr; + unsigned char buffr[9]; + + fprintf(stderr, " Address | Size | Offset | 00 01 02 03 04 05 06 07 | ASCII \n"); + fprintf(stderr, "---------+--------+---------+-------------------------+---------\n"); + for (ptr = (unsigned char *) buff, j = 0; j < count; j += 8) { + fprintf(stderr, " %8p | %06lu | %07x | ", buff, (unsigned long) count, (unsigned int) j); + l = ((count - j < 8) ? (count - j) : (8)); + memset(buffr, 0, 9); + memcpy(buffr, ptr + j, l); + for (k = 0; k < l; k++) { + fprintf(stderr, "%02x ", buffr[k]); + } + for (; k < 8; k++) { + fprintf(stderr, " "); + } + fprintf(stderr, "| %-8s\n", safe_str((char *) buffr, l)); + } +} |