summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--.cvsignore7
-rw-r--r--Makefile.am15
-rw-r--r--README28
-rw-r--r--acconfig.h10
-rw-r--r--acinclude.m4249
-rwxr-xr-xautogen.sh43
-rw-r--r--configure.in221
-rw-r--r--debug.c36
-rw-r--r--libast-config.in42
-rw-r--r--libast.h383
-rw-r--r--libast.spec.in42
-rw-r--r--libast_internal.h68
-rw-r--r--mem.c450
-rw-r--r--msgs.c81
-rw-r--r--snprintf.c521
-rw-r--r--strings.c549
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
diff --git a/README b/README
new file mode 100644
index 0000000..d7cb370
--- /dev/null
+++ b/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.
+"
diff --git a/debug.c b/debug.c
new file mode 100644
index 0000000..e8b14df
--- /dev/null
+++ b/debug.c
@@ -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_ */
diff --git a/mem.c b/mem.c
new file mode 100644
index 0000000..4a4daa0
--- /dev/null
+++ b/mem.c
@@ -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
diff --git a/msgs.c b/msgs.c
new file mode 100644
index 0000000..901b9c4
--- /dev/null
+++ b/msgs.c
@@ -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));
+ }
+}