mirror of
https://github.com/Orc/discount.git
synced 2026-09-25 04:10:00 +03:00
Check all of the bits of markdown into version control before
some horrible catastrophe happens
This commit is contained in:
+31
@@ -0,0 +1,31 @@
|
||||
CC=@CC@
|
||||
BINDIR=@exedir@
|
||||
MANDIR=@mandir@
|
||||
|
||||
PGM=markdown
|
||||
|
||||
all: $(PGM)
|
||||
|
||||
install: $(PGM)
|
||||
@INSTALL_PROGRAM@ $(PGM) $(BINDIR)
|
||||
@MKSUID@ $(BINDIR)/$(PGM)
|
||||
|
||||
# install.man:
|
||||
# @INSTALL_DIR@ $(MANDIR)/man1
|
||||
# @INSTALL_DATA@ pstree.1 $(MANDIR)/man1
|
||||
|
||||
$(PGM): markdown.c
|
||||
$(CC) -o $(PGM) -DPROGRAM=1 markdown.c @LIBS@
|
||||
|
||||
# version.o: VERSION
|
||||
# echo 'char version[] = VERSION;' > version.c
|
||||
# $(CC) -DVERSION=\"`cat VERSION`\" -c version.c
|
||||
|
||||
clean:
|
||||
rm -f $(PGM) *.o
|
||||
|
||||
distclean spotless: clean
|
||||
rm -f @GENERATED_FILES@ @CONFIGURE_FILES@
|
||||
|
||||
|
||||
markdown.o: markdown.c config.h cstring.h
|
||||
Executable
+1376
@@ -0,0 +1,1376 @@
|
||||
# @(#) configure.inc 1.42@(#)
|
||||
# Copyright (c) 1999-2007 David Parsons. All rights reserved.
|
||||
#
|
||||
# Redistribution and use in source and binary forms, with or without
|
||||
# modification, are permitted provided that the following conditions
|
||||
# are met:
|
||||
# 1. Redistributions of source code must retain the above copyright
|
||||
# notice, this list of conditions and the following disclaimer.
|
||||
# 2. Redistributions in binary form must reproduce the above copyright
|
||||
# notice, this list of conditions and the following disclaimer in
|
||||
# the documentation and/or other materials provided with the
|
||||
# distribution.
|
||||
# 3. My name may not be used to endorse or promote products derived
|
||||
# from this software without specific prior written permission.
|
||||
#
|
||||
# THIS SOFTWARE IS PROVIDED BY DAVID PARSONS ``AS IS'' AND ANY
|
||||
# EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
|
||||
# THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A
|
||||
# PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL DAVID
|
||||
# PARSONS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
|
||||
# EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED
|
||||
# TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||
# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
|
||||
# ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
|
||||
# LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING
|
||||
# IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
|
||||
# THE POSSIBILITY OF SUCH DAMAGE.
|
||||
#
|
||||
|
||||
|
||||
#
|
||||
# this preamble code is executed when this file is sourced and it picks
|
||||
# interesting things off the command line.
|
||||
#
|
||||
ac_default_path="/sbin:/usr/sbin:/bin:/usr/bin:/usr/local/bin:/usr/X11R6/bin"
|
||||
|
||||
ac_standard="--src=DIR where the source lives (.)
|
||||
--prefix=DIR where to install the final product (/usr/local)
|
||||
--execdir=DIR where to put executables (prefix/bin)
|
||||
--sbindir=DIR where to put static executables (prefix/sbin)
|
||||
--confdir=DIR where to put configuration information (/etc)
|
||||
--libdir=DIR where to put libraries (prefix/lib)
|
||||
--libexecdir=DIR where to put private executables
|
||||
--mandir=DIR where to put manpages"
|
||||
|
||||
__fail=exit
|
||||
|
||||
if dirname B/A 2>/dev/null >/dev/null; then
|
||||
__ac_dirname() {
|
||||
dirname "$1"
|
||||
}
|
||||
else
|
||||
__ac_dirname() {
|
||||
echo "$1" | sed -e 's:/[^/]*$::'
|
||||
}
|
||||
fi
|
||||
|
||||
ac_progname=$0
|
||||
ac_configure_command=
|
||||
Q=\'
|
||||
for x in "$@"; do
|
||||
ac_configure_command="$ac_configure_command $Q$x$Q"
|
||||
done
|
||||
# ac_configure_command="$*"
|
||||
|
||||
__d=`__ac_dirname "$ac_progname"`
|
||||
if [ "$__d" = "$ac_progname" ]; then
|
||||
AC_SRCDIR=`pwd`
|
||||
else
|
||||
AC_SRCDIR=`cd $__d;pwd`
|
||||
fi
|
||||
|
||||
__ac_dir() {
|
||||
if test -d "$1"; then
|
||||
(cd "$1";pwd)
|
||||
else
|
||||
echo "$1";
|
||||
fi
|
||||
}
|
||||
|
||||
while [ $# -gt 0 ]; do
|
||||
unset matched
|
||||
|
||||
case X"$1" in
|
||||
X--src|X--srcdir)
|
||||
AC_SRCDIR=`__ac_dir "$2"`
|
||||
_set_srcdir=1
|
||||
shift 2;;
|
||||
|
||||
X--src=*|X--srcdir=*)
|
||||
__d=`echo "$1" | sed -e 's/^[^=]*=//'`
|
||||
AC_SRCDIR=`__ac_dir "$__d"`
|
||||
_set_srcdir=1
|
||||
shift 1 ;;
|
||||
|
||||
X--prefix)
|
||||
AC_PREFIX=`__ac_dir "$2"`
|
||||
_set_prefix=1
|
||||
shift 2;;
|
||||
|
||||
X--prefix=*)
|
||||
__d=`echo "$1"| sed -e 's/^[^=]*=//'`
|
||||
AC_PREFIX=`__ac_dir "$__d"`
|
||||
_set_prefix=1
|
||||
shift 1;;
|
||||
|
||||
X--confdir)
|
||||
AC_CONFDIR=`__ac_dir "$2"`
|
||||
_set_confdir=1
|
||||
shift 2;;
|
||||
|
||||
X--confdir=*)
|
||||
__d=`echo "$1" | sed -e 's/^[^=]*=//'`
|
||||
AC_CONFDIR=`__ac_dir "$__d"`
|
||||
_set_confdir=1
|
||||
shift 1;;
|
||||
|
||||
X--libexec|X--libexecdir)
|
||||
AC_LIBEXEC=`__ac_dir "$2"`
|
||||
_set_libexec=1
|
||||
shift 2;;
|
||||
|
||||
X--libexec=*|X--libexecdir=*)
|
||||
__d=`echo "$1" | sed -e 's/^[^=]*=//'`
|
||||
AC_LIBEXEC=`__ac_dir "$__d"`
|
||||
_set_libexec=1
|
||||
shift 1;;
|
||||
|
||||
X--lib|X--libdir)
|
||||
AC_LIBDIR=`__ac_dir "$2"`
|
||||
_set_libdir=1
|
||||
shift 2;;
|
||||
|
||||
X--lib=*|X--libdir=*)
|
||||
__d=`echo "$1" | sed -e 's/^[^=]*=//'`
|
||||
AC_LIBDIR=`__ac_dir "$__d"`
|
||||
_set_libdir=1
|
||||
shift 1;;
|
||||
|
||||
X--exec|X--execdir)
|
||||
AC_EXECDIR=`__ac_dir "$2"`
|
||||
_set_execdir=1
|
||||
shift 2;;
|
||||
|
||||
X--exec=*|X--execdir=*)
|
||||
__d=`echo "$1" | sed -e 's/^[^=]*=//'`
|
||||
AC_EXECDIR=`__ac_dir "$__d"`
|
||||
_set_execdir=1
|
||||
shift 1;;
|
||||
|
||||
X--sbin|X--sbindir)
|
||||
AC_SBINDIR=`__ac_dir "$2"`
|
||||
_set_sbindir=1
|
||||
shift 2;;
|
||||
|
||||
X--sbin=*|X--sbindir=*)
|
||||
__d=`echo "$1" | sed -e 's/^[^=]*=//'`
|
||||
AC_SBINDIR=`__ac_dir "$__d"`
|
||||
_set_sbindir=1
|
||||
shift 1;;
|
||||
|
||||
X--man|X--mandir)
|
||||
AC_MANDIR=`__ac_dir "$2"`
|
||||
_set_mandir=1
|
||||
shift 2;;
|
||||
|
||||
X--man=*|X--mandir=*)
|
||||
__d=`echo "$1" | sed -e 's/^[^=]*=//'`
|
||||
AC_MANDIR=`__ac_dir "$__d"`
|
||||
_set_mandir=1
|
||||
shift 1;;
|
||||
|
||||
X--use-*=*)
|
||||
_var=`echo "$1"| sed -n 's/^--use-\([A-Za-z][-A-Za-z0-9_]*\)=.*$/\1/p'`
|
||||
if [ "$_var" ]; then
|
||||
_val=`echo "$1" | sed -e 's/^--use-[^=]*=\(.*\)$/\1/'`
|
||||
_v=`echo $_var | tr '[a-z]' '[A-Z]' | tr '-' '_'`
|
||||
case X"$_val" in
|
||||
X[Yy][Ee][Ss]|X[Tt][Rr][Uu][Ee]) eval USE_${_v}=T ;;
|
||||
X[Nn][Oo]|X[Ff][Aa][Ll][Ss][Ee]) eval unset USE_${_v} ;;
|
||||
*) echo "Bad value for --use-$_var ; must be yes or no"
|
||||
exit 1 ;;
|
||||
esac
|
||||
else
|
||||
echo "Bad option $1. Use --help to show options" 1>&2
|
||||
exit 1
|
||||
fi
|
||||
shift 1 ;;
|
||||
|
||||
X--use-*)
|
||||
_var=`echo "$1"|sed -n 's/^--use-\([A-Za-z][-A-Za-z0-9_]*\)$/\1/p'`
|
||||
_v=`echo $_var | tr '[a-z]' '[A-Z]' | tr '-' '_'`
|
||||
eval USE_${_v}=T
|
||||
shift 1;;
|
||||
|
||||
X--with-*=*)
|
||||
_var=`echo "$1"| sed -n 's/^--with-\([A-Za-z][-A-Za-z0-9_]*\)=.*$/\1/p'`
|
||||
if [ "$_var" ]; then
|
||||
_val=`echo "$1" | sed -e 's/^--with-[^=]*=\(.*\)$/\1/'`
|
||||
_v=`echo $_var | tr '[a-z]' '[A-Z]' | tr '-' '_'`
|
||||
eval WITH_${_v}=\"$_val\"
|
||||
else
|
||||
echo "Bad option $1. Use --help to show options" 1>&2
|
||||
exit 1
|
||||
fi
|
||||
shift 1 ;;
|
||||
|
||||
X--with-*)
|
||||
_var=`echo "$1" | sed -n 's/^--with-\([A-Za-z][A-Za-z0-9_-]*\)$/\1/p'`
|
||||
if [ "$_var" ]; then
|
||||
_v=`echo $_var | tr '[a-z]' '[A-Z]' | tr '-' '_'`
|
||||
eval WITH_${_v}=1
|
||||
else
|
||||
echo "Bad option $1. Use --help to show options" 1>&2
|
||||
exit 1
|
||||
fi
|
||||
shift 1 ;;
|
||||
|
||||
X--help)
|
||||
echo "$ac_standard"
|
||||
test "$ac_help" && echo "$ac_help"
|
||||
exit 0;;
|
||||
|
||||
*) if [ "$LOCAL_AC_OPTIONS" ]; then
|
||||
eval "$LOCAL_AC_OPTIONS"
|
||||
else
|
||||
ac_error=T
|
||||
fi
|
||||
if [ "$ac_error" ]; then
|
||||
echo "Bad option $1. Use --help to show options" 1>&2
|
||||
exit 1
|
||||
fi ;;
|
||||
esac
|
||||
done
|
||||
|
||||
|
||||
#
|
||||
# echo w/o newline
|
||||
#
|
||||
echononl()
|
||||
{
|
||||
${ac_echo:-echo} "${@}$ac_echo_nonl"
|
||||
}
|
||||
|
||||
#
|
||||
# log something to the terminal and to a logfile.
|
||||
#
|
||||
LOG () {
|
||||
echo "$@"
|
||||
echo "$@" 1>&5
|
||||
}
|
||||
|
||||
#
|
||||
# log something to the terminal without a newline, and to a logfile with
|
||||
# a newline
|
||||
#
|
||||
LOGN () {
|
||||
echononl "$@" 1>&5
|
||||
echo "$@"
|
||||
}
|
||||
|
||||
#
|
||||
# log something to the terminal
|
||||
#
|
||||
TLOG () {
|
||||
echo "$@" 1>&5
|
||||
}
|
||||
|
||||
#
|
||||
# log something to the terminal, no newline
|
||||
#
|
||||
TLOGN () {
|
||||
echononl "$@" 1>&5
|
||||
}
|
||||
|
||||
|
||||
#
|
||||
# AC_CONTINUE tells configure not to bomb if something fails, but to
|
||||
# continue blithely along
|
||||
#
|
||||
AC_CONTINUE () {
|
||||
__fail="return"
|
||||
}
|
||||
|
||||
|
||||
#
|
||||
# generate a .o file from sources
|
||||
#
|
||||
__MAKEDOTO() {
|
||||
AC_PROG_CC
|
||||
|
||||
if $AC_CC -c -o /tmp/doto$$.o "$@" $AC_LIBS 2>/tmp/doto$$.err; then
|
||||
rm -f /tmp/doto$$.o /tmp/doto$$.err
|
||||
TLOG " (found)"
|
||||
return 0
|
||||
fi
|
||||
rm -f /tmp/doto$$.o
|
||||
TLOG " (not found)"
|
||||
echo "test failed: command was $AC_CC -c -o /tmp/doto$$.o" "$@" $AC_LIBS
|
||||
echo "output:"
|
||||
cat /tmp/doto$$.err
|
||||
rm -f /tmp/doto$$.err
|
||||
echo "offending sources:"
|
||||
for x in "$@"; do
|
||||
echo "$x:"
|
||||
cat $x
|
||||
done
|
||||
return 1
|
||||
}
|
||||
|
||||
|
||||
#
|
||||
# Emulate gnu autoconf's AC_CHECK_HEADERS() function
|
||||
#
|
||||
AC_CHECK_HEADERS () {
|
||||
|
||||
echo "/* AC_CHECK_HEADERS */" > /tmp/ngc$$.c
|
||||
for hdr in $*; do
|
||||
echo "#include <$hdr>" >> /tmp/ngc$$.c
|
||||
done
|
||||
echo "main() { }" >> /tmp/ngc$$.c
|
||||
|
||||
LOGN "checking for header $hdr"
|
||||
|
||||
if __MAKEDOTO /tmp/ngc$$.c; then
|
||||
AC_DEFINE 'HAVE_'`echo $hdr | tr 'a-z' 'A-Z' | tr './' '_'` 1
|
||||
rc=0
|
||||
else
|
||||
rc=1
|
||||
fi
|
||||
rm -f /tmp/ngc$$.c
|
||||
return $rc
|
||||
}
|
||||
|
||||
|
||||
#
|
||||
# emulate GNU autoconf's AC_CHECK_FUNCS function
|
||||
#
|
||||
AC_CHECK_FUNCS () {
|
||||
AC_PROG_CC
|
||||
|
||||
F=$1
|
||||
shift
|
||||
rm -f /tmp/ngc$$.c
|
||||
|
||||
while [ "$1" ]; do
|
||||
echo "#include <$1>" >> /tmp/ngc$$.c
|
||||
shift
|
||||
done
|
||||
|
||||
cat >> /tmp/ngc$$.c << EOF
|
||||
main()
|
||||
{
|
||||
|
||||
$F();
|
||||
}
|
||||
EOF
|
||||
|
||||
LOGN "checking for the $F function"
|
||||
|
||||
if $AC_CC -o /tmp/ngc$$ /tmp/ngc$$.c $LIBS; then
|
||||
AC_DEFINE `echo ${2:-HAVE_$F} | tr 'a-z' 'A-Z'` 1
|
||||
TLOG " (found)"
|
||||
rc=0
|
||||
else
|
||||
echo "offending command was:"
|
||||
cat /tmp/ngc$$.c
|
||||
echo "$AC_CC -o /tmp/ngc$$ /tmp/ngc$$.c $LIBS"
|
||||
TLOG " (not found)"
|
||||
rc=1
|
||||
fi
|
||||
rm -f /tmp/ngc$$.c /tmp/ngc$$
|
||||
return $rc
|
||||
}
|
||||
|
||||
|
||||
#
|
||||
# check to see if some structure exists
|
||||
#
|
||||
# usage: AC_CHECK_STRUCT structure {include ...}
|
||||
#
|
||||
AC_CHECK_STRUCT () {
|
||||
struct=$1
|
||||
shift
|
||||
|
||||
rm -f /tmp/ngc$$.c
|
||||
|
||||
for include in $*; do
|
||||
echo "#include <$include>" >> /tmp/ngc$$.c
|
||||
done
|
||||
|
||||
cat >> /tmp/ngc$$.c << EOF
|
||||
main()
|
||||
{
|
||||
struct $struct foo;
|
||||
}
|
||||
EOF
|
||||
|
||||
LOGN "checking for struct $struct"
|
||||
|
||||
if __MAKEDOTO /tmp/ngc$$.c; then
|
||||
AC_DEFINE HAVE_STRUCT_`echo ${struct} | tr 'a-z' 'A-Z'`
|
||||
rc=0
|
||||
else
|
||||
rc=1
|
||||
fi
|
||||
rm -f /tmp/ngc$$.c
|
||||
return $rc
|
||||
}
|
||||
|
||||
|
||||
#
|
||||
# check to see if some type exists
|
||||
#
|
||||
# usage: AC_CHECK_TYPE type {include ...}
|
||||
#
|
||||
AC_CHECK_TYPE () {
|
||||
type=$1
|
||||
shift
|
||||
|
||||
rm -f /tmp/ngc$$.c
|
||||
|
||||
for include in $*; do
|
||||
echo "#include <$include>" >> /tmp/ngc$$.c
|
||||
done
|
||||
|
||||
cat >> /tmp/ngc$$.c << EOF
|
||||
main()
|
||||
{
|
||||
$type foo;
|
||||
}
|
||||
EOF
|
||||
|
||||
LOGN "checking for $type type"
|
||||
|
||||
if __MAKEDOTO /tmp/ngc$$.c; then
|
||||
AC_DEFINE HAVE_TYPE_`echo ${type} | tr 'a-z' 'A-Z'`
|
||||
rc=0
|
||||
else
|
||||
rc=1
|
||||
fi
|
||||
rm -f /tmp/ngc$$.c
|
||||
return $rc
|
||||
}
|
||||
|
||||
|
||||
#
|
||||
# check to see if some structure contains a field
|
||||
#
|
||||
# usage: AC_CHECK_FIELD structure field {include ...}
|
||||
#
|
||||
AC_CHECK_FIELD () {
|
||||
|
||||
struct=$1
|
||||
field=$2
|
||||
shift 2
|
||||
|
||||
rm -f /tmp/ngc$$.c
|
||||
|
||||
for include in $*;do
|
||||
echo "#include <$include>" >> /tmp/ngc$$.c
|
||||
done
|
||||
|
||||
cat >> /tmp/ngc$$.c << EOF
|
||||
main()
|
||||
{
|
||||
struct $struct foo;
|
||||
|
||||
foo.$field;
|
||||
}
|
||||
EOF
|
||||
|
||||
LOGN "checking that struct $struct has a $field field"
|
||||
|
||||
if __MAKEDOTO /tmp/ngc$$.c; then
|
||||
AC_DEFINE HAVE_`echo ${struct}_$field | tr 'a-z' 'A-Z'`
|
||||
rc=0
|
||||
else
|
||||
rc=1
|
||||
fi
|
||||
rm -f /tmp/ngc$$.c
|
||||
return $rc
|
||||
}
|
||||
|
||||
|
||||
#
|
||||
# check that the C compiler works
|
||||
#
|
||||
AC_PROG_CC () {
|
||||
test "$AC_CC" && return 0
|
||||
|
||||
cat > /tmp/ngc$$.c << \EOF
|
||||
#include <stdio.h>
|
||||
main()
|
||||
{
|
||||
puts("hello, sailor");
|
||||
}
|
||||
EOF
|
||||
|
||||
TLOGN "checking the C compiler"
|
||||
|
||||
unset AC_CFLAGS AC_LDFLAGS
|
||||
|
||||
if [ "$CC" ] ; then
|
||||
AC_CC="$CC"
|
||||
elif [ "$WITH_PATH" ]; then
|
||||
AC_CC=`acLookFor cc`
|
||||
elif [ "`acLookFor cc`" ]; then
|
||||
# don't specify the full path if the user is looking in their $PATH
|
||||
# for a C compiler.
|
||||
AC_CC=cc
|
||||
fi
|
||||
|
||||
# finally check for POSIX c89
|
||||
test "$AC_CC" || AC_CC=`acLookFor c89`
|
||||
|
||||
if [ ! "$AC_CC" ]; then
|
||||
TLOG " (no C compiler found)"
|
||||
$__fail 1
|
||||
fi
|
||||
echo "checking out the C compiler"
|
||||
|
||||
$AC_CC -o /tmp/ngc$$ /tmp/ngc$$.c
|
||||
status=$?
|
||||
|
||||
TLOGN " ($AC_CC)"
|
||||
if [ $status -eq 0 ]; then
|
||||
TLOG " ok"
|
||||
|
||||
# check that the CFLAGS and LDFLAGS aren't bogus
|
||||
|
||||
unset AC_CFLAGS AC_LDFLAGS
|
||||
|
||||
if [ "$CFLAGS" ]; then
|
||||
test "$CFLAGS" && echo "validating CFLAGS=${CFLAGS}"
|
||||
if $AC_CC $CFLAGS -o /tmp/ngc$$.o /tmp/ngc$$.c ; then
|
||||
AC_CFLAGS=${CFLAGS:-"-g"}
|
||||
test "$CFLAGS" && echo "CFLAGS=\"${CFLAGS}\" are okay"
|
||||
elif [ "$CFLAGS" ]; then
|
||||
echo "ignoring bogus CFLAGS=\"${CFLAGS}\""
|
||||
fi
|
||||
else
|
||||
AC_CFLAGS=-g
|
||||
fi
|
||||
if [ "$LDFLAGS" ]; then
|
||||
test "$LDFLAGS" && echo "validating LDFLAGS=${LDFLAGS}"
|
||||
if $AC_CC $LDFLAGS -o /tmp/ngc$$ /tmp/ngc$$.o; then
|
||||
AC_LDFLAGS=${LDFLAGS:-"-g"}
|
||||
test "$LDFLAGS" && TLOG "LDFLAGS=\"${LDFLAGS}\" are okay"
|
||||
elif [ "$LDFLAGS" ]; then
|
||||
TLOG "ignoring bogus LDFLAGS=\"${LDFLAGS}\""
|
||||
fi
|
||||
else
|
||||
AC_LDFLAGS=${CFLAGS:-"-g"}
|
||||
fi
|
||||
else
|
||||
AC_FAIL " does not compile code properly"
|
||||
fi
|
||||
|
||||
AC_SUB 'CC' "$AC_CC"
|
||||
|
||||
rm -f /tmp/ngc$$ /tmp/ngc$$.c /tmp/ngc$$.o
|
||||
|
||||
return $status
|
||||
}
|
||||
|
||||
|
||||
#
|
||||
# acLookFor actually looks for a program, without setting anything.
|
||||
#
|
||||
acLookFor () {
|
||||
path=${AC_PATH:-$ac_default_path}
|
||||
case "X$1" in
|
||||
X-[rx]) __mode=$1
|
||||
shift
|
||||
;;
|
||||
*) __mode=-x
|
||||
;;
|
||||
esac
|
||||
oldifs="$IFS"
|
||||
for program in $*; do
|
||||
IFS=":"
|
||||
for x in $path; do
|
||||
if [ $__mode $x/$program -a -f $x/$program ]; then
|
||||
echo $x/$program
|
||||
break 2
|
||||
fi
|
||||
done
|
||||
done
|
||||
IFS="$oldifs"
|
||||
unset __mode
|
||||
}
|
||||
|
||||
|
||||
#
|
||||
# check that a program exists and set its path
|
||||
#
|
||||
MF_PATH_INCLUDE () {
|
||||
SYM=$1; shift
|
||||
|
||||
case X$1 in
|
||||
X-[rx]) __mode=$1
|
||||
shift
|
||||
;;
|
||||
*) unset __mode
|
||||
;;
|
||||
esac
|
||||
|
||||
TLOGN "looking for $1"
|
||||
|
||||
DEST=`acLookFor $__mode $*`
|
||||
|
||||
__sym=`echo "$SYM" | tr '[a-z]' '[A-Z]'`
|
||||
if [ "$DEST" ]; then
|
||||
TLOG " ($DEST)"
|
||||
echo "$1 is $DEST"
|
||||
AC_MAK $SYM
|
||||
AC_DEFINE PATH_$__sym \""$DEST"\"
|
||||
AC_SUB $__sym "$DEST"
|
||||
eval CF_$SYM=$DEST
|
||||
return 0
|
||||
else
|
||||
#AC_SUB $__sym ''
|
||||
echo "$1 is not found"
|
||||
TLOG " (not found)"
|
||||
return 1
|
||||
fi
|
||||
}
|
||||
|
||||
|
||||
#
|
||||
# AC_INIT starts the ball rolling
|
||||
#
|
||||
# After AC_INIT, fd's 1 and 2 point to config.log
|
||||
# and fd 5 points to what used to be fd 1
|
||||
#
|
||||
AC_INIT () {
|
||||
__config_files="config.cmd config.sub config.h config.mak config.log"
|
||||
rm -f $__config_files
|
||||
__cwd=`pwd`
|
||||
exec 5>&1 1>$__cwd/config.log 2>&1
|
||||
AC_CONFIGURE_FOR=__AC_`echo $1 | sed -e 's/\..$//' | tr 'a-z' 'A-Z' | tr ' ' '_'`_D
|
||||
|
||||
# check to see whether to use echo -n or echo ...\c
|
||||
#
|
||||
echo -n hello > $$
|
||||
echo world >> $$
|
||||
if grep "helloworld" $$ >/dev/null; then
|
||||
ac_echo="echo -n"
|
||||
echo "[echo -n] works"
|
||||
else
|
||||
ac_echo="echo"
|
||||
echo 'hello\c' > $$
|
||||
echo 'world' >> $$
|
||||
if grep "helloworld" $$ >/dev/null; then
|
||||
ac_echo_nonl='\c'
|
||||
echo "[echo ...\\c] works"
|
||||
fi
|
||||
fi
|
||||
rm -f $$
|
||||
|
||||
LOG "Configuring for [$1]"
|
||||
|
||||
cat > $__cwd/config.h << EOF
|
||||
/*
|
||||
* configuration for $1${2:+" ($2)"}, generated `date`
|
||||
* by ${LOGNAME:-`whoami`}@`hostname`
|
||||
*/
|
||||
#ifndef $AC_CONFIGURE_FOR
|
||||
#define $AC_CONFIGURE_FOR 1
|
||||
|
||||
|
||||
EOF
|
||||
|
||||
unset __share
|
||||
if [ -d $AC_PREFIX/share/man ]; then
|
||||
for t in 1 2 3 4 5 6 7 8 9; do
|
||||
if [ -d $AC_PREFIX/share/man/man$t ]; then
|
||||
__share=/share
|
||||
elif [ -d $AC_PREFIX/share/man/cat$t ]; then
|
||||
__share=/share
|
||||
fi
|
||||
done
|
||||
else
|
||||
__share=
|
||||
fi
|
||||
|
||||
if [ -d $AC_PREFIX/libexec ]; then
|
||||
__libexec=libexec
|
||||
else
|
||||
__libexec=lib
|
||||
fi
|
||||
|
||||
|
||||
AC_PREFIX=${AC_PREFIX:-/usr/local}
|
||||
AC_EXECDIR=${AC_EXECDIR:-$AC_PREFIX/bin}
|
||||
AC_SBINDIR=${AC_SBINDIR:-$AC_PREFIX/sbin}
|
||||
AC_LIBDIR=${AC_LIBDIR:-$AC_PREFIX/lib}
|
||||
AC_MANDIR=${AC_MANDIR:-$AC_PREFIX$__share/man}
|
||||
AC_LIBEXEC=${AC_LIBEXEC:-$AC_PREFIX/$__libexec}
|
||||
AC_CONFDIR=${AC_CONFDIR:-/etc}
|
||||
|
||||
AC_PATH=${WITH_PATH:-$PATH}
|
||||
AC_PROG_CPP
|
||||
AC_PROG_INSTALL
|
||||
|
||||
ac_os=`uname -s`
|
||||
_os=`echo $ac_os | tr '[a-z]' '[A-Z]'`
|
||||
AC_DEFINE OS_$_os 1
|
||||
eval OS_${_os}=1
|
||||
unset _os
|
||||
}
|
||||
|
||||
|
||||
#
|
||||
# AC_LIBRARY checks to see if a given library exists and contains the
|
||||
# given function.
|
||||
# usage: AC_LIBRARY function library [alternate ...]
|
||||
#
|
||||
AC_LIBRARY() {
|
||||
SRC=$1
|
||||
shift
|
||||
|
||||
__acllibs=
|
||||
__aclhdrs=
|
||||
|
||||
for x in "$@"; do
|
||||
case X"$x" in
|
||||
X-l*) __acllibs="$__acllibs $x" ;;
|
||||
*) __aclhdrs="$__aclhdrs $x" ;;
|
||||
esac
|
||||
done
|
||||
|
||||
# first see if the function can be found in any of the
|
||||
# current libraries
|
||||
AC_QUIET AC_CHECK_FUNCS $SRC $__aclhdrs && return 0
|
||||
|
||||
# then search through the list of libraries
|
||||
__libs="$LIBS"
|
||||
for x in $__acllibs; do
|
||||
LIBS="$__libs $x"
|
||||
if AC_QUIET AC_CHECK_FUNCS $SRC $__aclhdrs; then
|
||||
AC_LIBS="$AC_LIBS $x"
|
||||
return 0
|
||||
fi
|
||||
done
|
||||
return 1
|
||||
}
|
||||
|
||||
|
||||
#
|
||||
# AC_PROG_LEX checks to see if LEX exists, and if it's lex or flex.
|
||||
#
|
||||
AC_PROG_LEX() {
|
||||
TLOGN "looking for lex "
|
||||
|
||||
DEST=`acLookFor lex`
|
||||
if [ "$DEST" ]; then
|
||||
AC_MAK LEX
|
||||
AC_DEFINE PATH_LEX \"$DEST\"
|
||||
AC_SUB 'LEX' "$DEST"
|
||||
echo "lex is $DEST"
|
||||
else
|
||||
DEST=`acLookFor flex`
|
||||
if [ "$DEST" ]; then
|
||||
AC_MAK FLEX
|
||||
AC_DEFINE 'LEX' \"$DEST\"
|
||||
AC_SUB 'LEX', "$DEST"
|
||||
echo "lex is $DEST"
|
||||
else
|
||||
AC_SUB LEX ''
|
||||
echo "neither lex or flex found"
|
||||
TLOG " (not found)"
|
||||
return 1
|
||||
fi
|
||||
fi
|
||||
|
||||
if AC_LIBRARY yywrap -ll -lfl; then
|
||||
TLOG "($DEST)"
|
||||
return 0
|
||||
fi
|
||||
TLOG "(no lex library found)"
|
||||
return 1
|
||||
}
|
||||
|
||||
|
||||
#
|
||||
# AC_PROG_YACC checks to see if YACC exists, and if it's bison or
|
||||
# not.
|
||||
#
|
||||
AC_PROG_YACC () {
|
||||
|
||||
TLOGN "looking for yacc "
|
||||
|
||||
DEST=`acLookFor yacc`
|
||||
if [ "$DEST" ]; then
|
||||
AC_MAK YACC
|
||||
AC_DEFINE PATH_YACC \"$DEST\"
|
||||
AC_SUB 'YACC' "$DEST"
|
||||
TLOG "($DEST)"
|
||||
echo "yacc is $DEST"
|
||||
else
|
||||
DEST=`acLookFor bison`
|
||||
if [ "$DEST" ]; then
|
||||
AC_MAK BISON
|
||||
AC_DEFINE 'YACC' \"$DEST\"
|
||||
AC_SUB 'YACC' "$DEST -y"
|
||||
echo "yacc is $DEST -y"
|
||||
TLOG "($DEST -y)"
|
||||
else
|
||||
AC_SUB 'YACC' ''
|
||||
echo "neither yacc or bison found"
|
||||
TLOG " (not found)"
|
||||
return 1
|
||||
fi
|
||||
fi
|
||||
return 0
|
||||
}
|
||||
|
||||
|
||||
#
|
||||
# AC_PROG_LN_S checks to see if ln exists, and, if so, if ln -s works
|
||||
#
|
||||
AC_PROG_LN_S () {
|
||||
test "$AC_FIND_PROG" || AC_PROG_FIND
|
||||
|
||||
test "$AC_FIND_PROG" || return 1
|
||||
|
||||
TLOGN "looking for \"ln -s\""
|
||||
DEST=`acLookFor ln`
|
||||
|
||||
if [ "$DEST" ]; then
|
||||
rm -f /tmp/b$$
|
||||
$DEST -s /tmp/a$$ /tmp/b$$
|
||||
if [ "`$AC_FIND_PROG /tmp/b$$ -type l -print`" ]; then
|
||||
TLOG " ($DEST)"
|
||||
echo "$DEST exists, and ln -s works"
|
||||
AC_SUB 'LN_S' "$DEST -s"
|
||||
rm -f /tmp/b$$
|
||||
else
|
||||
AC_SUB 'LN_S' ''
|
||||
TLOG " ($DEST exists, but -s does not seem to work)"
|
||||
echo "$DEST exists, but ln -s doesn't seem to work"
|
||||
rm -f /tmp/b$$
|
||||
return 1
|
||||
fi
|
||||
else
|
||||
AC_SUB 'LN_S' ''
|
||||
echo "ln not found"
|
||||
TLOG " (not found)"
|
||||
return 1
|
||||
fi
|
||||
}
|
||||
|
||||
|
||||
#
|
||||
# AC_PROG_FIND looks for the find program and sets the FIND environment
|
||||
# variable
|
||||
#
|
||||
AC_PROG_FIND () {
|
||||
if test -z "$AC_FIND_PROG"; then
|
||||
MF_PATH_INCLUDE FIND find
|
||||
rc=$?
|
||||
AC_FIND_PROG=$DEST
|
||||
return $rc
|
||||
fi
|
||||
return 0
|
||||
}
|
||||
|
||||
|
||||
#
|
||||
# AC_PROG_AWK looks for the awk program and sets the AWK environment
|
||||
# variable
|
||||
#
|
||||
AC_PROG_AWK () {
|
||||
if test -z "$AC_AWK_PROG"; then
|
||||
MF_PATH_INCLUDE AWK awk
|
||||
rc=$?
|
||||
AC_AWK_PROG=$DEST
|
||||
return $rc
|
||||
fi
|
||||
return 0
|
||||
}
|
||||
|
||||
|
||||
#
|
||||
# AC_PROG_SED looks for the sed program and sets the SED environment
|
||||
# variable
|
||||
#
|
||||
AC_PROG_SED () {
|
||||
if test -z "$AC_SED_PROG"; then
|
||||
MF_PATH_INCLUDE SED sed
|
||||
rc=$?
|
||||
AC_SED_PROG=$DEST
|
||||
return $rc
|
||||
fi
|
||||
return 0
|
||||
}
|
||||
|
||||
|
||||
#
|
||||
# AC_HEADER_SYS_WAIT looks for sys/wait.h
|
||||
#
|
||||
AC_HEADER_SYS_WAIT () {
|
||||
AC_CHECK_HEADERS sys/wait.h || return 1
|
||||
}
|
||||
|
||||
#
|
||||
# AC_TYPE_PID_T checks to see if the pid_t type exists
|
||||
#
|
||||
AC_TYPE_PID_T () {
|
||||
|
||||
AC_CHECK_TYPE pid_t sys/types.h
|
||||
return $?
|
||||
}
|
||||
|
||||
|
||||
#
|
||||
# AC_C_CONST checks to see if the compiler supports the const keyword
|
||||
#
|
||||
AC_C_CONST () {
|
||||
cat > /tmp/pd$$.c << EOF
|
||||
const char me=1;
|
||||
EOF
|
||||
LOGN "checking for \"const\" keyword"
|
||||
|
||||
if __MAKEDOTO /tmp/pd$$.c; then
|
||||
rc=0
|
||||
else
|
||||
AC_DEFINE 'const' '/**/'
|
||||
rc=1
|
||||
fi
|
||||
rm -f /tmp/pd$$.c
|
||||
return $rc
|
||||
}
|
||||
|
||||
|
||||
#
|
||||
# AC_C_VOLATILE checks to see if the compiler supports the volatile keyword
|
||||
#
|
||||
AC_C_VOLATILE () {
|
||||
cat > /tmp/pd$$.c << EOF
|
||||
f() { volatile char me=1; }
|
||||
EOF
|
||||
LOGN "checking for \"volatile\" keyword"
|
||||
|
||||
if __MAKEDOTO /tmp/pd$$.c; then
|
||||
rc=0
|
||||
else
|
||||
AC_DEFINE 'volatile' '/**/'
|
||||
rc=1
|
||||
fi
|
||||
rm -f /tmp/pd$$.c
|
||||
return $rc
|
||||
}
|
||||
|
||||
|
||||
#
|
||||
# AC_SCALAR_TYPES checks to see if the compiler can generate 2 and 4 byte ints.
|
||||
#
|
||||
AC_SCALAR_TYPES () {
|
||||
cat > /tmp/pd$$.c << EOF
|
||||
#include <stdio.h>
|
||||
main()
|
||||
{
|
||||
unsigned long v_long;
|
||||
unsigned int v_int;
|
||||
unsigned short v_short;
|
||||
|
||||
if (sizeof v_long == 4)
|
||||
puts("#define DWORD unsigned long");
|
||||
else if (sizeof v_int == 4)
|
||||
puts("#define DWORD unsigned int");
|
||||
else
|
||||
exit(1);
|
||||
|
||||
if (sizeof v_int == 2)
|
||||
puts("#define WORD unsigned int");
|
||||
else if (sizeof v_short == 2)
|
||||
puts("#define WORD unsigned short");
|
||||
else
|
||||
exit(2);
|
||||
puts("#define BYTE unsigned char");
|
||||
exit(0);
|
||||
}
|
||||
EOF
|
||||
rc=1
|
||||
LOGN "defining WORD & DWORD scalar types"
|
||||
if $AC_CC /tmp/pd$$.c -o /tmp/pd$$; then
|
||||
if /tmp/pd$$ >> $__cwd/config.h; then
|
||||
rc=0
|
||||
fi
|
||||
fi
|
||||
case "$rc" in
|
||||
0) TLOG "" ;;
|
||||
*) TLOG " ** FAILED **" ;;
|
||||
esac
|
||||
rm -f /tmp/pd$$ /tmp/pd$$.c
|
||||
}
|
||||
|
||||
|
||||
#
|
||||
# AC_OUTPUT generates makefiles from makefile.in's
|
||||
#
|
||||
AC_OUTPUT () {
|
||||
cd $__cwd
|
||||
AC_SUB 'LIBS' "$AC_LIBS"
|
||||
AC_SUB 'CONFIGURE_FILES' "$__config_files"
|
||||
AC_SUB 'GENERATED_FILES' "$*"
|
||||
AC_SUB 'CFLAGS' "$AC_CFLAGS"
|
||||
AC_SUB 'LDFLAGS' "$AC_LDFLAGS"
|
||||
AC_SUB 'srcdir' "$AC_SRCDIR"
|
||||
AC_SUB 'prefix' "$AC_PREFIX"
|
||||
AC_SUB 'exedir' "$AC_EXECDIR"
|
||||
AC_SUB 'sbindir' "$AC_SBINDIR"
|
||||
AC_SUB 'libdir' "$AC_LIBDIR"
|
||||
AC_SUB 'libexec' "$AC_LIBEXEC"
|
||||
AC_SUB 'confdir' "$AC_CONFDIR"
|
||||
AC_SUB 'mandir' "$AC_MANDIR"
|
||||
|
||||
if [ -r config.sub ]; then
|
||||
test "$AC_SED_PROG" || AC_PROG_SED
|
||||
test "$AC_SED_PROG" || return 1
|
||||
|
||||
echo >> config.h
|
||||
echo "#endif/* ${AC_CONFIGURE_FOR} */" >> config.h
|
||||
|
||||
rm -f config.cmd
|
||||
Q=\'
|
||||
cat - > config.cmd << EOF
|
||||
#! /bin/sh
|
||||
${CC:+CC=${Q}${CC}${Q}} ${CFLAGS:+CFLAGS=${Q}${CFLAGS}${Q}} $ac_progname $ac_configure_command
|
||||
EOF
|
||||
chmod +x config.cmd
|
||||
|
||||
__d=$AC_SRCDIR
|
||||
for makefile in $*;do
|
||||
if test -r $__d/${makefile}.in; then
|
||||
LOG "generating $makefile"
|
||||
./config.md `__ac_dirname ./$makefile` 2>/dev/null
|
||||
$AC_SED_PROG -f config.sub < $__d/${makefile}.in > $makefile
|
||||
__config_files="$__config_files $makefile"
|
||||
else
|
||||
LOG "WARNING: ${makefile}.in does not exist!"
|
||||
fi
|
||||
done
|
||||
unset __d
|
||||
|
||||
else
|
||||
echo
|
||||
fi
|
||||
}
|
||||
|
||||
#
|
||||
# AC_CHECK_FLOCK checks to see if flock() exists and if the LOCK_NB argument
|
||||
# works properly.
|
||||
#
|
||||
AC_CHECK_FLOCK() {
|
||||
|
||||
AC_CHECK_HEADERS sys/types.h sys/file.h fcntl.h
|
||||
|
||||
cat << EOF > $$.c
|
||||
#include <stdio.h>
|
||||
#include <sys/file.h>
|
||||
#include <sys/types.h>
|
||||
#include <fcntl.h>
|
||||
|
||||
main()
|
||||
{
|
||||
int x = open("$$.c", O_RDWR, 0666);
|
||||
int y = open("$$.c", O_RDWR, 0666);
|
||||
|
||||
if (flock(x, LOCK_EX) != 0)
|
||||
exit(1);
|
||||
if (flock(y, LOCK_EX|LOCK_NB) == 0)
|
||||
exit(1);
|
||||
exit(0);
|
||||
}
|
||||
EOF
|
||||
|
||||
LOGN "checking for flock()"
|
||||
HAS_FLOCK=0
|
||||
if $AC_CC -o flock $$.c ; then
|
||||
if ./flock ; then
|
||||
LOG " (found)"
|
||||
HAS_FLOCK=1
|
||||
AC_DEFINE HAS_FLOCK
|
||||
else
|
||||
LOG " (bad)"
|
||||
fi
|
||||
else
|
||||
LOG " (no)"
|
||||
fi
|
||||
|
||||
rm -f flock $$.c
|
||||
|
||||
case "$HAS_FLOCK" in
|
||||
0) return 1 ;;
|
||||
*) return 0 ;;
|
||||
esac
|
||||
}
|
||||
|
||||
|
||||
#
|
||||
# AC_CHECK_RESOLVER finds out whether the berkeley resolver is
|
||||
# present on this system.
|
||||
#
|
||||
AC_CHECK_RESOLVER () {
|
||||
AC_PROG_CC
|
||||
|
||||
TLOGN "checking for the Berkeley resolver library"
|
||||
|
||||
__ACR_rc=0
|
||||
|
||||
cat > /tmp/ngc$$.c << EOF
|
||||
#include <sys/types.h>
|
||||
#include <netinet/in.h>
|
||||
#include <arpa/nameser.h>
|
||||
#include <resolv.h>
|
||||
|
||||
main()
|
||||
{
|
||||
char bfr[256];
|
||||
|
||||
res_init();
|
||||
res_query("hello", C_IN, T_A, bfr, sizeof bfr);
|
||||
}
|
||||
EOF
|
||||
|
||||
if $AC_CC -o /tmp/ngc$$ /tmp/ngc$$.c; then
|
||||
TLOG " (found)"
|
||||
elif $AC_CC -o /tmp/ngc$$ /tmp/ngc$$.c -lresolv; then
|
||||
TLOG " (found, needs -lresolv)"
|
||||
AC_LIBS="$AC_LIBS -lresolv"
|
||||
elif $AC_CC -DBIND_8_COMPAT -o /tmp/ngc$$ /tmp/ngc$$.c; then
|
||||
TLOG " (found, needs BIND_8_COMPAT)"
|
||||
AC_DEFINE BIND_8_COMPAT 1
|
||||
elif $AC_CC -DBIND_8_COMPAT -o /tmp/ngc$$ /tmp/ngc$$.c -lresolv; then
|
||||
TLOG " (found, needs BIND_8_COMPAT & -lresolv)"
|
||||
AC_DEFINE BIND_8_COMPAT 1
|
||||
else
|
||||
TLOG " (not found)"
|
||||
__ACR_rc=1
|
||||
fi
|
||||
rm -f /tmp/ngc$$.c
|
||||
return $__ACR_rc
|
||||
}
|
||||
|
||||
|
||||
#
|
||||
# AC_CHECK_ALLOCA looks for alloca
|
||||
#
|
||||
AC_CHECK_ALLOCA () {
|
||||
|
||||
AC_PROG_CC
|
||||
AC_CHECK_HEADERS stdlib.h
|
||||
|
||||
cat - > /tmp/ngc$$.c << EOF
|
||||
#if T
|
||||
# include <alloca.h>
|
||||
#else
|
||||
# include <stdlib.h>
|
||||
#endif
|
||||
main()
|
||||
{
|
||||
alloca(10);
|
||||
}
|
||||
EOF
|
||||
|
||||
LOGN "checking for the alloca function"
|
||||
if $AC_CC -DT /tmp/ngc$$.c -o /tmp/ngc$$; then
|
||||
AC_DEFINE 'HAVE_ALLOCA_H' 1
|
||||
status=0
|
||||
TLOG " (found in alloca.h)"
|
||||
elif $AC_CC /tmp/ngc$$.c -o /tmp/ngc$$; then
|
||||
TLOG " (found)"
|
||||
status=0
|
||||
else
|
||||
TLOG " (not found)"
|
||||
status=1
|
||||
fi
|
||||
rm -f /tmp/ngc$$.c /tmp/ngc
|
||||
return $status
|
||||
|
||||
}
|
||||
|
||||
|
||||
#
|
||||
# AC_PROG_INSTALL finds the install program and guesses whether it's a
|
||||
# Berkeley or GNU install program
|
||||
#
|
||||
AC_PROG_INSTALL () {
|
||||
|
||||
DEST=`acLookFor install`
|
||||
|
||||
LOGN "checking for install"
|
||||
unset IS_BSD
|
||||
if [ "$DEST" ]; then
|
||||
# BSD install or GNU install? Let's find out...
|
||||
touch /tmp/a$$
|
||||
|
||||
$DEST /tmp/a$$ /tmp/b$$
|
||||
|
||||
if test -r /tmp/a$$; then
|
||||
LOG " ($DEST)"
|
||||
else
|
||||
IS_BSD=1
|
||||
LOG " ($DEST) bsd install"
|
||||
fi
|
||||
rm -f /tmp/a$$ /tmp/b$$
|
||||
else
|
||||
DEST=`acLookFor ginstall`
|
||||
if [ "$DEST" ]; then
|
||||
LOG " ($DEST)"
|
||||
else
|
||||
DEST="false"
|
||||
LOG " (not found)"
|
||||
fi
|
||||
fi
|
||||
|
||||
if [ "$IS_BSD" ]; then
|
||||
PROG_INSTALL="$DEST -c"
|
||||
else
|
||||
PROG_INSTALL="$DEST"
|
||||
fi
|
||||
|
||||
AC_SUB 'INSTALL' "$PROG_INSTALL"
|
||||
AC_SUB 'INSTALL_PROGRAM' "$PROG_INSTALL -s -m 755"
|
||||
AC_SUB 'INSTALL_DATA' "$PROG_INSTALL -m 444"
|
||||
|
||||
# finally build a little directory installer
|
||||
# if mkdir -p works, use that, otherwise use install -d,
|
||||
# otherwise build a script to do it by hand.
|
||||
# in every case, test to see if the directory exists before
|
||||
# making it.
|
||||
|
||||
if mkdir -p $$a/b; then
|
||||
# I like this method best.
|
||||
__mkdir="mkdir -p"
|
||||
rmdir $$a/b
|
||||
rmdir $$a
|
||||
elif $PROG_INSTALL -d $$a/b; then
|
||||
__mkdir="$PROG_INSTALL -d"
|
||||
rmdir $$a/b
|
||||
rmdir $$a
|
||||
fi
|
||||
|
||||
__config_files="$__config_files config.md"
|
||||
AC_SUB 'INSTALL_DIR' "$__cwd/config.md"
|
||||
echo "#! /bin/sh" > $__cwd/config.md
|
||||
echo "# script generated" `date` "by configure.sh" >> $__cwd/config.md
|
||||
echo >> $__cwd/config.md
|
||||
if [ "$__mkdir" ]; then
|
||||
echo "test -d \"\$1\" || $__mkdir \"\$1\"" >> $__cwd/config.md
|
||||
echo "exit $?" >> $__cwd/config.md
|
||||
else
|
||||
cat - >> $__cwd/config.md << \EOD
|
||||
pieces=`IFS=/; for x in $1; do echo $x; done`
|
||||
dir=
|
||||
for x in $pieces; do
|
||||
dir="$dir$x"
|
||||
mkdir $dir || exit 1
|
||||
dir="$dir/"
|
||||
done
|
||||
exit 0
|
||||
EOD
|
||||
fi
|
||||
chmod +x $__cwd/config.md
|
||||
}
|
||||
|
||||
#
|
||||
# acCheckCPP is a local that runs a C preprocessor with a given set of
|
||||
# compiler options
|
||||
#
|
||||
acCheckCPP () {
|
||||
cat > /tmp/ngc$$.c << EOF
|
||||
#define FOO BAR
|
||||
|
||||
FOO
|
||||
EOF
|
||||
|
||||
if $1 $2 /tmp/ngc$$.c > /tmp/ngc$$.o; then
|
||||
if grep -v '#define' /tmp/ngc$$.o | grep -s BAR >/dev/null; then
|
||||
echo "CPP=[$1], CPPFLAGS=[$2]"
|
||||
AC_SUB 'CPP' "$1"
|
||||
AC_SUB 'CPPFLAGS' "$2"
|
||||
rm /tmp/ngc$$.c /tmp/ngc$$.o
|
||||
return 0
|
||||
fi
|
||||
fi
|
||||
rm /tmp/ngc$$.c /tmp/ngc$$.o
|
||||
return 1
|
||||
}
|
||||
|
||||
|
||||
#
|
||||
# AC_PROG_CPP checks for cpp, then checks to see which CPPFLAGS are needed
|
||||
# to run it as a filter.
|
||||
#
|
||||
AC_PROG_CPP () {
|
||||
if [ "$AC_CPP_PROG" ]; then
|
||||
DEST=$AC_CPP_PROG
|
||||
else
|
||||
__ac_path="$AC_PATH"
|
||||
AC_PATH="/lib:/usr/lib:${__ac_path:-$ac_default_path}"
|
||||
DEST=`acLookFor cpp`
|
||||
AC_PATH="$__ac_path"
|
||||
fi
|
||||
|
||||
unset fail
|
||||
LOGN "Looking for cpp"
|
||||
if [ "$DEST" ]; then
|
||||
TLOGN " ($DEST)"
|
||||
acCheckCPP $DEST "$CPPFLAGS" || \
|
||||
acCheckCPP $DEST -traditional-cpp -E || \
|
||||
acCheckCPP $DEST -E || \
|
||||
acCheckCPP $DEST -traditional-cpp -pipe || \
|
||||
acCheckCPP $DEST -pipe || fail=1
|
||||
|
||||
if [ "$fail" ]; then
|
||||
AC_FAIL " (can't run cpp as a pipeline)"
|
||||
else
|
||||
TLOG " ok"
|
||||
return 0
|
||||
fi
|
||||
fi
|
||||
AC_FAIL " (not found)"
|
||||
}
|
||||
|
||||
#
|
||||
# AC_FAIL spits out an error message, then __fail's
|
||||
AC_FAIL() {
|
||||
LOG "$*"
|
||||
$__fail 1
|
||||
}
|
||||
|
||||
#
|
||||
# AC_SUB writes a substitution into config.sub
|
||||
AC_SUB() {
|
||||
( echononl "s;@$1@;"
|
||||
_subst=`echo $2 | sed -e 's/;/\\;/g'`
|
||||
echononl "$_subst"
|
||||
echo ';g' ) >> $__cwd/config.sub
|
||||
}
|
||||
|
||||
#
|
||||
# AC_MAK writes a define into config.mak
|
||||
AC_MAK() {
|
||||
echo "HAVE_$1 = 1" >> $__cwd/config.mak
|
||||
}
|
||||
|
||||
#
|
||||
# AC_DEFINE adds a #define to config.h
|
||||
AC_DEFINE() {
|
||||
echo "#define $1 ${2:-1}" >> $__cwd/config.h
|
||||
}
|
||||
|
||||
#
|
||||
# AC_INCLUDE adds a #include to config.h
|
||||
AC_INCLUDE() {
|
||||
echo "#include \"$1\"" >> $__cwd/config.h
|
||||
}
|
||||
|
||||
#
|
||||
# AC_CONFIG adds a configuration setting to all the config files
|
||||
AC_CONFIG() {
|
||||
AC_DEFINE "PATH_$1" \""$2"\"
|
||||
AC_MAK "$1"
|
||||
AC_SUB "$1" "$2"
|
||||
}
|
||||
|
||||
#
|
||||
# AC_QUIET does something quietly
|
||||
AC_QUIET() {
|
||||
eval $* 5>/dev/null
|
||||
}
|
||||
Executable
+29
@@ -0,0 +1,29 @@
|
||||
#! /bin/sh
|
||||
|
||||
# local options: ac_help is the help message that describes them
|
||||
# and LOCAL_AC_OPTIONS is the script that interprets them. LOCAL_AC_OPTIONS
|
||||
# is a script that's processed with eval, so you need to be very careful to
|
||||
# make certain that what you quote is what you want to quote.
|
||||
|
||||
# load in the configuration file
|
||||
#
|
||||
TARGET=markdown
|
||||
. ./configure.inc
|
||||
|
||||
AC_INIT $TARGET
|
||||
|
||||
AC_PROG_CC
|
||||
|
||||
case "$AC_CC $AC_CFLAGS" in
|
||||
*-Wall*) AC_DEFINE 'while(x)' 'while( (x) != 0 )'
|
||||
AC_DEFINE 'if(x)' 'if( (x) != 0 )' ;;
|
||||
esac
|
||||
|
||||
AC_C_VOLATILE
|
||||
AC_C_CONST
|
||||
AC_SCALAR_TYPES
|
||||
AC_CHECK_ALLOCA || AC_FAIL "$TARGET requires alloca()"
|
||||
|
||||
[ "$OS_FREEBSD" -o "$OS_DRAGONFLY" ] || AC_CHECK_HEADERS malloc.h
|
||||
|
||||
AC_OUTPUT Makefile
|
||||
@@ -0,0 +1,49 @@
|
||||
/* two template types: STRING(t) which defines a pascal-style string
|
||||
* of element (t) [STRING(char) is the closest to the pascal string],
|
||||
* and ANCHOR(t) which defines a baseplate that a linked list can be
|
||||
* built up from. [The linked list /must/ contain a ->next pointer
|
||||
* for linking the list together with.]
|
||||
*/
|
||||
#ifndef _CSTRING_D
|
||||
#define _CSTRING_D
|
||||
|
||||
#include <stdlib.h>
|
||||
|
||||
/* expandable Pascal-style string.
|
||||
*/
|
||||
#define STRING(type) struct { type *text; int size, alloc; }
|
||||
|
||||
#define RESERVE(x,c) (x).text = malloc(sizeof T(x)[0] * (((x).size=0),((x).alloc=(c))) )
|
||||
#define CREATE(x) RESERVE(x,100)
|
||||
#define EXPAND(x) (x).text[((x).size < (x).alloc \
|
||||
? 0 \
|
||||
: !((x).text = realloc((x).text, sizeof T(x)[0] * ((x).alloc += 100)))), \
|
||||
(x).size++]
|
||||
|
||||
#define DELETE(x) (x).alloc ? (free(T(x)), S(x) x.alloc = 0) \
|
||||
: ( S(x) = 0 )
|
||||
#define CLIP(t,i,sz) \
|
||||
( ((i) >= 0) && ((sz) > 0) && (((i)+(sz)) <= S(t)) ) ? \
|
||||
(memmove(&T(t)[i], &T(t)[i+sz], (S(t)-(i+sz)+1)*sizeof(T(t)[0])), \
|
||||
S(t) -= (sz)) : -1
|
||||
|
||||
/* reference-style links (and images) are stored in an array
|
||||
*/
|
||||
#define T(x) (x).text
|
||||
#define S(x) (x).size
|
||||
|
||||
/* abstract anchor type that defines a list base
|
||||
* with a function that attaches an element to
|
||||
* the end of the list.
|
||||
*
|
||||
* the list base field is named .text so that the T()
|
||||
* macro will work with it.
|
||||
*/
|
||||
#define ANCHOR(t) struct { t *text, *end; }
|
||||
|
||||
#define ATTACH(t, p) ( (t).text ?( ((t).end->next = (p)), ((t).end = (p)) ) \
|
||||
:( ((t).text = (t).end = (p)) ) )
|
||||
|
||||
typedef STRING(char) Cstring;
|
||||
|
||||
#endif/*_CSTRING_D*/
|
||||
+1314
@@ -0,0 +1,1314 @@
|
||||
/* markdown: a C implementation of John Gruber's Markdown markup language.
|
||||
*/
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
#include <stdarg.h>
|
||||
#include <stdlib.h>
|
||||
#include <time.h>
|
||||
#include "cstring.h"
|
||||
|
||||
/* prefixes for <automatic links>
|
||||
*/
|
||||
static char *autoprefix[] = { "http://", "https://", "ftp://", "news://" };
|
||||
#define SZAUTOPREFIX (sizeof autoprefix / sizeof autoprefix[0])
|
||||
|
||||
/* block-level tags for passing html blocks through the blender
|
||||
*/
|
||||
static char *blocktags[] = { "ADDRESS", "BDO", "BLOCKQUOTE", "CENTER",
|
||||
"DFN", "DIV", "H1", "H2", "H3", "H4",
|
||||
"H5", "H6", "LISTING", "NOBR", "UL",
|
||||
"P", "OL", "DL", "PLAINTEXT", "PRE",
|
||||
"WBR", "XMP" };
|
||||
#define SZBLOCKTAGS (sizeof blocktags / sizeof blocktags[0])
|
||||
|
||||
/* reference-style links (and images) are stored in an array
|
||||
* of footnotes.
|
||||
*/
|
||||
typedef struct footnote {
|
||||
Cstring tag; /* the tag for the reference link */
|
||||
Cstring link; /* what this footnote points to */
|
||||
Cstring title; /* what it's called (TITLE= attribute) */
|
||||
int height, width; /* dimensions (for image link) */
|
||||
} Footnote;
|
||||
|
||||
static STRING(Footnote) footnotes;
|
||||
|
||||
|
||||
/* each input line is read into a Line, which contains the line,
|
||||
* the offset of the first non-space character [this assumes
|
||||
* that all tabs will be expanded to spaces!], and a pointer to
|
||||
* the next line.
|
||||
*/
|
||||
typedef struct line {
|
||||
Cstring text;
|
||||
struct line *next;
|
||||
int dle;
|
||||
} Line;
|
||||
|
||||
|
||||
/* a paragraph is a collection of Lines, with links to the next paragraph
|
||||
* and (if it's a QUOTE, UL, or OL) to the reparsed contents of this
|
||||
* paragraph.
|
||||
*/
|
||||
typedef struct paragraph {
|
||||
struct paragraph *next; /* next paragraph */
|
||||
struct paragraph *down; /* recompiled contents of this paragraph */
|
||||
struct line *text; /* all the text in this paragraph */
|
||||
enum { FORCED, CODE=1, QUOTE, MARKUP, HTML, UL, OL, HR } typ;
|
||||
int para;
|
||||
enum { LEFT, RIGHT, CENTER} align;
|
||||
} Paragraph;
|
||||
|
||||
|
||||
/* case insensitive string sort (for qsort() and bsearch() of block tags)
|
||||
*/
|
||||
static int
|
||||
casort(char **a, char **b)
|
||||
{
|
||||
return strcasecmp(*a,*b);
|
||||
}
|
||||
|
||||
|
||||
/* case insensitive string sort for Footnote tags.
|
||||
*/
|
||||
static int
|
||||
footsort(Footnote *a, Footnote *b)
|
||||
{
|
||||
return strcasecmp(T(a->tag), T(b->tag));
|
||||
}
|
||||
|
||||
|
||||
/* see if a <tag> is one of the block tags that frames a html
|
||||
* paragraph.
|
||||
*/
|
||||
static char *
|
||||
isblocktag(char *tag)
|
||||
{
|
||||
char **r=bsearch(&tag, blocktags, SZBLOCKTAGS, sizeof blocktags[0], casort);
|
||||
|
||||
return r ? (*r) : 0;
|
||||
}
|
||||
|
||||
|
||||
/* find the first blank character after position <i>
|
||||
*/
|
||||
static int
|
||||
nextblank(Line *t, int i)
|
||||
{
|
||||
while ( (i < S(t->text)) && !isspace(T(t->text)[i]) )
|
||||
++i;
|
||||
return i;
|
||||
}
|
||||
|
||||
|
||||
/* find the next nonblank character after position <i>
|
||||
*/
|
||||
static int
|
||||
nextnonblank(Line *t, int i)
|
||||
{
|
||||
while ( (i < S(t->text)) && isspace(T(t->text)[i]) )
|
||||
++i;
|
||||
return i;
|
||||
}
|
||||
|
||||
|
||||
/* find the first nonblank character on the Line.
|
||||
*/
|
||||
static int
|
||||
firstnonblank(Line *p)
|
||||
{
|
||||
return nextnonblank(p,0);
|
||||
}
|
||||
|
||||
|
||||
/* read in the markdown source document, assemble into a linked
|
||||
* list. Tabs ('\t') will be expanded to spaces here to make
|
||||
* the rest of the compilation easier.
|
||||
*/
|
||||
Line *
|
||||
in(FILE *input)
|
||||
{
|
||||
int i, c, xp;
|
||||
Line *p;
|
||||
|
||||
ANCHOR(Line) list = { 0, 0 };
|
||||
|
||||
p = calloc(sizeof *p, 1);
|
||||
CREATE(p->text);
|
||||
xp = 0;
|
||||
|
||||
for (; (c = getc(input)) != EOF; ) {
|
||||
if (c == '\n') {
|
||||
/* add a trailing null, then exclude it from
|
||||
* the string size
|
||||
*/
|
||||
EXPAND(p->text) = 0;
|
||||
--S(p->text);
|
||||
|
||||
p->dle = firstnonblank(p);
|
||||
|
||||
ATTACH(list, p);
|
||||
|
||||
p = calloc(sizeof *p, 1);
|
||||
CREATE(p->text);
|
||||
xp = 0;
|
||||
}
|
||||
else if ( c != '\t' ) {
|
||||
EXPAND(p->text) = c;
|
||||
xp++;
|
||||
}
|
||||
else {
|
||||
/* expand tabs into 1..4 spaces. This is not
|
||||
* the traditional tab spacing, but the language
|
||||
* definition /really really/ wants tabs to be
|
||||
* 4 spaces wide (indents are in terms of tabs
|
||||
* *or* 4 spaces.
|
||||
*/
|
||||
do {
|
||||
EXPAND(p->text) = ' ';
|
||||
} while ( ++xp & 03 );
|
||||
}
|
||||
}
|
||||
if ( S(p->text) ) {
|
||||
/* It's not an error if the input doesn't end on a newline
|
||||
*/
|
||||
EXPAND(p->text) = 0;
|
||||
--S(p->text);
|
||||
|
||||
p->dle = firstnonblank(p);
|
||||
|
||||
ATTACH(list, p);
|
||||
}
|
||||
return T(list);
|
||||
}
|
||||
|
||||
|
||||
static Cstring output;
|
||||
static unsigned int csp = 0;
|
||||
|
||||
static int
|
||||
push(char *t, int s)
|
||||
{
|
||||
int i;
|
||||
|
||||
for (i=0; i < s; i++)
|
||||
EXPAND(output) = t[i];
|
||||
}
|
||||
|
||||
|
||||
/* look <i> characters ahead of the cursor.
|
||||
*/
|
||||
static int
|
||||
peek(int i)
|
||||
{
|
||||
|
||||
if ( i > 0 )
|
||||
i += (csp-1);
|
||||
else
|
||||
i = (csp + i)-1;
|
||||
|
||||
return (i >= 0) && (i < S(output)) ? T(output)[i] : EOF;
|
||||
}
|
||||
|
||||
|
||||
static int
|
||||
pull()
|
||||
{
|
||||
if ( csp < S(output) ) return T(output)[csp++];
|
||||
|
||||
S(output) = csp = 0;
|
||||
return EOF;
|
||||
}
|
||||
|
||||
|
||||
static void
|
||||
skipblankc()
|
||||
{
|
||||
while ( isspace(peek(1)) )
|
||||
pull();
|
||||
}
|
||||
|
||||
|
||||
static void
|
||||
pullcopy(char *dest, int size)
|
||||
{
|
||||
while ( size-- > 0 )
|
||||
*dest++ = pull();
|
||||
*dest = 0;
|
||||
}
|
||||
|
||||
static void
|
||||
linkylinky(int image)
|
||||
{
|
||||
char *label;
|
||||
int labelsize, size;
|
||||
int qc, c, i, j;
|
||||
|
||||
for ( labelsize = 1; (c=peek(labelsize)) != ']'; ++labelsize)
|
||||
if ( c == EOF )
|
||||
return;
|
||||
|
||||
label = alloca(labelsize+1);
|
||||
pullcopy(label, labelsize);
|
||||
|
||||
skipblankc();
|
||||
|
||||
printf( image ? "<img" : "<a");
|
||||
|
||||
if ( (c=pull()) == '(' ) /* inline link */ {
|
||||
char *link;
|
||||
|
||||
for ( size =1; (c=peek(size)) != ')' && !isspace(c); ++size)
|
||||
if ( c == EOF )
|
||||
goto failed;
|
||||
|
||||
link = alloca(size);
|
||||
pullcopy(link, size-1);
|
||||
|
||||
printf(" %s=\"%.*s\"", image ? "src" : "href", size, link);
|
||||
skipblankc();
|
||||
|
||||
if ( image && (peek(1) == '=') ) {
|
||||
char *dim;
|
||||
int width, height;
|
||||
|
||||
pull();
|
||||
for (i=0; isdigit(c=peek(i+1)) || (c == 'x'); i++)
|
||||
;
|
||||
|
||||
if ( i ) {
|
||||
if ( sscanf(T(output)+csp, "%dx%d", &width, &height) == 2 )
|
||||
printf(" width=%d height=%d", width, height);
|
||||
while ( i-- ) pull();
|
||||
}
|
||||
skipblankc();
|
||||
}
|
||||
|
||||
if ( (qc=peek(1)) == '"' || qc == '\'' ) {
|
||||
printf(" title=\"");
|
||||
pull();
|
||||
while ( (c=pull()) != EOF && c != qc )
|
||||
putchar(c);
|
||||
putchar('"');
|
||||
}
|
||||
if ( peek(1) == ')' ) pull();
|
||||
}
|
||||
else if ( c == '[' ) { /* footnote link */
|
||||
char *tag;
|
||||
Footnote key, *ret;
|
||||
|
||||
for ( size = 0; (c=peek(size+1)) != ']'; ++size)
|
||||
if ( c == EOF )
|
||||
goto failed;
|
||||
|
||||
tag = alloca ( 2 + (size ? size : labelsize) );
|
||||
tag[0] = '[';
|
||||
|
||||
if ( size )
|
||||
pullcopy(tag+1, size+1);
|
||||
else {
|
||||
memcpy(tag+1, label, labelsize);
|
||||
tag[labelsize+1] = 0;
|
||||
pull(); /* discard the ']' from [] */
|
||||
}
|
||||
|
||||
T(key.tag) = tag;
|
||||
ret = bsearch(&key, T(footnotes), S(footnotes), sizeof key, footsort);
|
||||
|
||||
if ( ret ) {
|
||||
if ( S(ret->link) )
|
||||
printf(" %s=\"%.*s\"", image ? "src" : "href",
|
||||
S(ret->link), T(ret->link));
|
||||
if ( S(ret->title) )
|
||||
printf(" title=\"%.*s\"", S(ret->title), T(ret->title));
|
||||
|
||||
if ( image && ret->height && ret->width )
|
||||
printf(" height=%d width=%d", ret->height, ret->width);
|
||||
}
|
||||
}
|
||||
else
|
||||
return;
|
||||
|
||||
printf(image ? " alt=\"%.*s\"" : ">%.*s</a", labelsize-1, label);
|
||||
failed:
|
||||
putchar('>');
|
||||
}
|
||||
|
||||
|
||||
static char*
|
||||
hexfmt()
|
||||
{
|
||||
return (random()&1) ? "&#x%02x;" : "&#%02d;";
|
||||
}
|
||||
|
||||
|
||||
static int
|
||||
handle_less_than()
|
||||
{
|
||||
char *text;
|
||||
int c, size, i;
|
||||
int maybetag=1, maybelink=0, maybeaddress=0;
|
||||
|
||||
for ( size=0; ((c = peek(size+1)) != '>') && !isspace(c); size++ ) {
|
||||
if ( ! (c == '/' || isalnum(c)) )
|
||||
maybetag=0;
|
||||
if ( c == '@' )
|
||||
maybeaddress=1;
|
||||
else if ( c == EOF )
|
||||
return 0;
|
||||
}
|
||||
|
||||
if ( size == 0 )
|
||||
return 0;
|
||||
|
||||
if ( maybetag ) {
|
||||
putchar('<');
|
||||
return 1;
|
||||
}
|
||||
|
||||
text = alloca(size+2);
|
||||
pullcopy(text,size);
|
||||
|
||||
for ( i=0; i < SZAUTOPREFIX; i++ )
|
||||
if ( strncasecmp(text, autoprefix[i], strlen(autoprefix[i])) == 0 ) {
|
||||
printf("<a href=\"%s\">%s</a", text, text);
|
||||
return 1;
|
||||
}
|
||||
if ( maybeaddress ) {
|
||||
printf("<a href=\"");
|
||||
for ( i=0; text[i]; i++ )
|
||||
printf(hexfmt(), (unsigned char)text[i]);
|
||||
printf("\">");
|
||||
for ( i=0; text[i]; i++ )
|
||||
printf(hexfmt(), (unsigned char)text[i]);
|
||||
printf("</a>");
|
||||
return 1;
|
||||
}
|
||||
|
||||
printf("<%s", text);
|
||||
return 1;
|
||||
}
|
||||
|
||||
static void code(int);
|
||||
|
||||
static void
|
||||
text()
|
||||
{
|
||||
int c, j;
|
||||
int em = 0;
|
||||
int strong = 0;
|
||||
int dquo = 0;
|
||||
int squo = 0;
|
||||
|
||||
while ( (c = pull()) != EOF ) {
|
||||
switch (c) {
|
||||
case 0: break;
|
||||
|
||||
/* Markdown transformations (additional chrome is done at the end of this
|
||||
* switch)
|
||||
*/
|
||||
case '!': if ( peek(1) == '[' ) {
|
||||
pull();
|
||||
linkylinky(1);
|
||||
}
|
||||
else
|
||||
putchar(c);
|
||||
break;
|
||||
case '[': linkylinky(0);
|
||||
break;
|
||||
case '*':
|
||||
case '_': if (peek(1) == c) {
|
||||
pull();
|
||||
if ( c == strong ) {
|
||||
printf("</strong>");
|
||||
strong = 0;
|
||||
}
|
||||
else if ( strong == 0 ) {
|
||||
printf("<strong>");
|
||||
strong = c;
|
||||
}
|
||||
else {
|
||||
putchar(c);
|
||||
putchar(c);
|
||||
}
|
||||
}
|
||||
else {
|
||||
if (c == em ) {
|
||||
printf("</em>");
|
||||
em = 0;
|
||||
}
|
||||
else if ( em == 0 ) {
|
||||
printf("<em>");
|
||||
em = c;
|
||||
}
|
||||
else
|
||||
putchar(c);
|
||||
}
|
||||
break;
|
||||
|
||||
case '`': printf("<code>");
|
||||
if ( peek(1) == '`' ) {
|
||||
pull();
|
||||
code(2);
|
||||
}
|
||||
else
|
||||
code(1);
|
||||
break;
|
||||
|
||||
case '\\': if ( (c = pull()) == '&' )
|
||||
printf("&");
|
||||
else if ( c == '<' )
|
||||
printf("<");
|
||||
else
|
||||
putchar( c ? c : '\\');
|
||||
break;
|
||||
|
||||
case '<': if ( !handle_less_than() )
|
||||
printf("<");
|
||||
break;
|
||||
|
||||
case '&': j = (peek(1) == '#' ) ? 2 : 1;
|
||||
while ( isalnum(peek(j)) )
|
||||
++j;
|
||||
|
||||
if ( peek(j) != ';' )
|
||||
printf("&");
|
||||
else
|
||||
putchar(c);
|
||||
break;
|
||||
|
||||
default: putchar(c);
|
||||
break;
|
||||
|
||||
/* Smarty-pants-style chrome for quotes, -, ellipses, and (r)(c)(tm)
|
||||
*/
|
||||
case '"': printf("&%cdquo;", dquo ? 'r' : 'l' );
|
||||
dquo = !dquo;
|
||||
break;
|
||||
|
||||
#if 0
|
||||
case '\'': printf("&%csquo;", squo ? 'r' : 'l' );
|
||||
squo = !squo;
|
||||
break;
|
||||
#endif
|
||||
|
||||
case '.': if ( peek(1) == '.' && peek(2) == '.' ) {
|
||||
printf("…");
|
||||
pull();pull();
|
||||
}
|
||||
else
|
||||
putchar(c);
|
||||
break;
|
||||
|
||||
case '-': if ( peek(1) == '-' ) {
|
||||
printf("—");
|
||||
pull();
|
||||
}
|
||||
else if ( isspace(peek(-1)) && isspace(peek(1)) )
|
||||
printf("–");
|
||||
else
|
||||
putchar(c);
|
||||
break;
|
||||
|
||||
case '(': if ( (j = toupper(peek(1))) == 'R' || j == 'C' ) {
|
||||
if ( peek(2) == ')' ) {
|
||||
printf( "&%s;", (j=='C') ? "copy" : "reg" );
|
||||
pull();pull();
|
||||
break;
|
||||
}
|
||||
}
|
||||
else if ( j == 'T' && toupper(peek(2)) == 'M'
|
||||
&& peek(3) == ')' ) {
|
||||
printf("™");
|
||||
pull();pull();pull();
|
||||
break;
|
||||
}
|
||||
putchar(c);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
static void
|
||||
code(int escape)
|
||||
{
|
||||
int c, j;
|
||||
|
||||
while ( (c = pull()) != EOF ) {
|
||||
switch (c) {
|
||||
case '`': switch (escape) {
|
||||
case 2: if ( peek(1) == '`' ) {
|
||||
pull();
|
||||
case 1: printf("</code>");
|
||||
return;
|
||||
}
|
||||
}
|
||||
putchar(c);
|
||||
break;
|
||||
|
||||
case '&': printf("&"); break;
|
||||
case '<': printf("<"); break;
|
||||
default: putchar(c); break;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
||||
static int
|
||||
alto(char *t, int s)
|
||||
{
|
||||
int i;
|
||||
|
||||
for (i=0; (i < s) && isalnum(t[i]); i++)
|
||||
;
|
||||
|
||||
return (i < s) ? i : 0;
|
||||
|
||||
|
||||
}
|
||||
|
||||
/* setext header; 2 lines, second is ==== or -----
|
||||
*/
|
||||
static int
|
||||
setext(Line *p)
|
||||
{
|
||||
char *q;
|
||||
int i;
|
||||
|
||||
if ( (p->next == 0) || p->next->next ) return 0;
|
||||
|
||||
q = T(p->next->text);
|
||||
if ( (*q == '=') || (*q == '-') ) {
|
||||
for (i=1; i < S(p->next->text); i++)
|
||||
if ( *q != T(p->next->text)[i] )
|
||||
return 0;
|
||||
|
||||
i = (*q == '=') ? 1 : 2;
|
||||
|
||||
printf("<H%d>", i);
|
||||
push(T(p->text), S(p->text)); text();
|
||||
printf("</H%d>\n", i);
|
||||
|
||||
return 1;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
/* etx header; # of #'s in front is the H level
|
||||
*/
|
||||
static int
|
||||
etx(Line *p)
|
||||
{
|
||||
int H = 0;
|
||||
int i, j;
|
||||
|
||||
if ( p->next ) return 0;
|
||||
|
||||
for ( i=0; T(p->text)[i] == '#'; ++i, ++H)
|
||||
;
|
||||
|
||||
if ( !H ) return 0;
|
||||
|
||||
i = nextnonblank(p, i);
|
||||
|
||||
j = S(p->text)-1;
|
||||
|
||||
while ( (j > i) && (T(p->text)[j] == '#') )
|
||||
--j;
|
||||
|
||||
while ( (j > 1) && isspace(T(p->text)[j]) )
|
||||
--j;
|
||||
|
||||
if ( j < i ) return 0;
|
||||
|
||||
printf("<H%d>", H);
|
||||
push(T(p->text)+i, 1+(j-i)); text();
|
||||
printf("</H%d>", H);
|
||||
return 1;
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
printblock(Line *t)
|
||||
{
|
||||
while (t) {
|
||||
if ( S(t->text) ) {
|
||||
if ( S(t->text) > 2 && T(t->text)[S(t->text)-2] == ' '
|
||||
&& T(t->text)[S(t->text)-1] == ' ') {
|
||||
push(T(t->text), S(t->text)-2);
|
||||
push("<br/>\n", 6);
|
||||
}
|
||||
else {
|
||||
push(T(t->text), S(t->text));
|
||||
push("\n", 1);
|
||||
}
|
||||
}
|
||||
t = t->next;
|
||||
}
|
||||
text();
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
printcode(Line *t)
|
||||
{
|
||||
int blanks;
|
||||
|
||||
for ( blanks = 0; t ; t = t->next )
|
||||
if ( S(t->text) ) {
|
||||
while ( blanks ) {
|
||||
push("\n", 1);
|
||||
--blanks;
|
||||
}
|
||||
push(T(t->text), S(t->text));
|
||||
push("\n", 1);
|
||||
}
|
||||
else blanks++;
|
||||
code(0);
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
printhtml(Line *t)
|
||||
{
|
||||
int blanks;
|
||||
|
||||
for ( blanks=0; t ; t = t->next )
|
||||
if ( S(t->text) ) {
|
||||
while ( blanks ) {
|
||||
putchar('\n');
|
||||
--blanks;
|
||||
}
|
||||
fwrite(T(t->text), S(t->text), 1, stdout);
|
||||
putchar('\n');
|
||||
}
|
||||
else
|
||||
blanks++;
|
||||
}
|
||||
|
||||
|
||||
static Paragraph *display(Paragraph*, int);
|
||||
|
||||
|
||||
static void
|
||||
emit(Paragraph *p)
|
||||
{
|
||||
int multiple = p->next;
|
||||
|
||||
while ( p = display(p, multiple) )
|
||||
;
|
||||
}
|
||||
|
||||
|
||||
static Paragraph*
|
||||
listdisplay(Paragraph *p)
|
||||
{
|
||||
int typ = p->typ;
|
||||
|
||||
printf( "<%cl>\n", (typ==UL)?'u':'o');
|
||||
|
||||
while ( p && (p->typ == typ) ) {
|
||||
printf("<li>");
|
||||
emit(p->down);
|
||||
printf("</li>");
|
||||
|
||||
p = p->next;
|
||||
}
|
||||
|
||||
printf( "</%cl>\n", (typ==UL)?'u':'o');
|
||||
return p;
|
||||
}
|
||||
|
||||
|
||||
static int
|
||||
nextislist(Paragraph *p)
|
||||
{
|
||||
return p && (p->typ == UL || p->typ == OL);
|
||||
}
|
||||
|
||||
|
||||
/* dump out a Paragraph in the desired manner
|
||||
*/
|
||||
static Paragraph*
|
||||
display(Paragraph *p, int multiple)
|
||||
{
|
||||
char *pp = 0;
|
||||
|
||||
switch ( p->typ ) {
|
||||
case FORCED:
|
||||
break;
|
||||
|
||||
case HTML:
|
||||
printhtml(p->text);
|
||||
break;
|
||||
|
||||
case CODE:
|
||||
printf("<p><code><pre>");
|
||||
printcode(p->text);
|
||||
puts("</pre></code></p>");
|
||||
break;
|
||||
|
||||
case QUOTE:
|
||||
printf("<blockquote>");
|
||||
emit(p->down);
|
||||
puts("</blockquote>");
|
||||
break;
|
||||
|
||||
case UL:
|
||||
case OL:
|
||||
return listdisplay(p);
|
||||
|
||||
case HR:
|
||||
puts("<HR>");
|
||||
break;
|
||||
|
||||
default:
|
||||
if ( p->align == CENTER )
|
||||
pp = "center";
|
||||
else if ( multiple && p->para )
|
||||
pp = "p";
|
||||
|
||||
if ( pp ) printf("<%s>", pp);
|
||||
if ( !(setext(p->text)||etx(p->text)) )
|
||||
printblock(p->text);
|
||||
if ( pp ) printf("</%s>\n", pp);
|
||||
break;
|
||||
}
|
||||
return p->next;
|
||||
}
|
||||
|
||||
|
||||
static int
|
||||
blankline(Line *p)
|
||||
{
|
||||
return ! (p && (S(p->text) > p->dle) );
|
||||
}
|
||||
|
||||
|
||||
static char *
|
||||
isopentag(Line *p)
|
||||
{
|
||||
int i=0, len;
|
||||
char *key;
|
||||
|
||||
if ( !p ) return 0;
|
||||
|
||||
len = S(p->text);
|
||||
|
||||
if ( len < 3 || T(p->text)[0] != '<' )
|
||||
return 0;
|
||||
|
||||
for (i=1; (i < len) && isalnum(T(p->text)[i]); ++i)
|
||||
/* skip over tag (don't care about arguments or '>' yet) */ ;
|
||||
|
||||
key = alloca(i);
|
||||
memcpy(key, T(p->text)+1, i-1);
|
||||
key[i-1] = 0;
|
||||
|
||||
return isblocktag(key);
|
||||
}
|
||||
|
||||
|
||||
static int
|
||||
isclosetag(Line *p, char *key, int siz)
|
||||
{
|
||||
int eol;
|
||||
|
||||
if ( !p ) return 0;
|
||||
|
||||
eol = S(p->text)-1;
|
||||
|
||||
if ( T(p->text)[eol] != '>' ) return 0;
|
||||
if ( strncasecmp(T(p->text)+(eol-siz), key, siz) != 0 ) return 0;
|
||||
if ( T(p->text)[eol-(siz+1)] != '/' ) return 0;
|
||||
if ( T(p->text)[eol-(siz+2)] != '<' ) return 0;
|
||||
return 1;
|
||||
}
|
||||
|
||||
|
||||
static Line *
|
||||
htmlblock(Paragraph *p, char *key)
|
||||
{
|
||||
Line *t, *ret;
|
||||
int keysize = strlen(key);
|
||||
|
||||
for ( t = p->text; t ; t = t->next)
|
||||
if ( isclosetag(t, key, keysize) && blankline(t->next) ) {
|
||||
ret = t->next;
|
||||
t->next = 0;
|
||||
return ret;
|
||||
}
|
||||
return t;
|
||||
}
|
||||
|
||||
|
||||
/* footnotes look like ^<whitespace>{0,3}[stuff]: <content>$
|
||||
*/
|
||||
static int
|
||||
isfootnote(Line *t)
|
||||
{
|
||||
int i;
|
||||
|
||||
if ( ( (i = t->dle) > 3) || (T(t->text)[i] != '[') )
|
||||
return 0;
|
||||
|
||||
for ( ; i < S(t->text) ; ++i ) {
|
||||
if ( T(t->text)[i] == ']' && T(t->text)[i+1] == ':' )
|
||||
return 1;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
static int
|
||||
islabel(char *line)
|
||||
{
|
||||
return strchr("*-+", line[0]) && isspace(line[1]);
|
||||
}
|
||||
|
||||
static int
|
||||
isquote(Line *t)
|
||||
{
|
||||
return ( T(t->text)[0] == '>' );
|
||||
}
|
||||
|
||||
|
||||
static int
|
||||
islist(Line *t, int *trim)
|
||||
{
|
||||
int i, j;
|
||||
char *q;
|
||||
|
||||
if ( (t == 0) || (t->dle > 3) )
|
||||
return 0;
|
||||
|
||||
if ( islabel(T(t->text) + t->dle) ) {
|
||||
i = nextnonblank(t, t->dle+1);
|
||||
*trim = i;
|
||||
return UL;
|
||||
}
|
||||
|
||||
if ( (j = nextblank(t,t->dle)) > t->dle ) {
|
||||
if ( T(t->text)[j-1] == '.' ) {
|
||||
strtoul(T(t->text)+t->dle, &q, 10);
|
||||
if ( q == T(t->text) + (j-1) ) {
|
||||
j = nextnonblank(t,j);
|
||||
*trim = j;
|
||||
return OL;
|
||||
}
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
static int
|
||||
dashchar(char c)
|
||||
{
|
||||
return (c == '*') || (c == '-') || (c == '_');
|
||||
}
|
||||
|
||||
|
||||
static int
|
||||
ishr(Line *t)
|
||||
{
|
||||
int i, count;
|
||||
char dash = 0;
|
||||
char c;
|
||||
|
||||
for ( i = 0, count = 1; i < S(t->text); i++) {
|
||||
c = T(t->text)[i];
|
||||
if ( dashchar(c) ) {
|
||||
if ( dash == c )
|
||||
++count;
|
||||
else if ( dash == 0 )
|
||||
dash = c;
|
||||
else
|
||||
return 0;
|
||||
}
|
||||
else if ( !isspace(c) )
|
||||
return 0;
|
||||
}
|
||||
return (count >= 3);
|
||||
}
|
||||
|
||||
|
||||
static int
|
||||
iscode(Line *t)
|
||||
{
|
||||
return (t->dle >= 4);
|
||||
}
|
||||
|
||||
|
||||
static int
|
||||
fancy(Line *t)
|
||||
{
|
||||
int trim;
|
||||
|
||||
return isquote(t) || iscode(t) || islist(t, &trim);
|
||||
}
|
||||
|
||||
|
||||
static Line *
|
||||
codeblock(Paragraph *p)
|
||||
{
|
||||
Line *t, *r, *ret;
|
||||
|
||||
for ( t = p->text; t; t = r ) {
|
||||
CLIP(t->text,0,4);
|
||||
t->dle = firstnonblank(t);
|
||||
|
||||
r = t->next;
|
||||
if ( r && S(r->text) && !iscode(r) ) {
|
||||
ret = t->next;
|
||||
t->next = 0;
|
||||
return ret;
|
||||
}
|
||||
}
|
||||
return t;
|
||||
}
|
||||
|
||||
|
||||
static int
|
||||
centered(Line *first, Line *last)
|
||||
{
|
||||
if ( first&&last ) {
|
||||
int len = S(last->text);
|
||||
|
||||
if ( (len > 2) && (strncmp(T(first->text), "->", 2) == 0)
|
||||
&& (strncmp(T(last->text)+len-2, "<-", 2) == 0) ) {
|
||||
CLIP(first->text, 0, 2);
|
||||
S(last->text) -= 2;
|
||||
return CENTER;
|
||||
}
|
||||
}
|
||||
return LEFT;
|
||||
}
|
||||
|
||||
|
||||
static Line *
|
||||
textblock(Paragraph *p)
|
||||
{
|
||||
Line *t, *r;
|
||||
|
||||
for ( t = p->text; t ; t = t->next ) {
|
||||
if ( (r = t->next) == 0 ) {
|
||||
p->para = 2;
|
||||
p->align = centered(p->text, t);
|
||||
return 0;
|
||||
}
|
||||
else if ( fancy(r) ){
|
||||
t->next = 0;
|
||||
return r;
|
||||
}
|
||||
else if ( blankline(r) ) {
|
||||
p->align = centered(p->text, t);
|
||||
p->para = 2;
|
||||
t->next = 0;
|
||||
return r;
|
||||
}
|
||||
}
|
||||
return t;
|
||||
}
|
||||
|
||||
|
||||
static Line *
|
||||
skipempty(Line *p)
|
||||
{
|
||||
while ( p && (p->dle == S(p->text)) )
|
||||
p = p->next;
|
||||
return p;
|
||||
}
|
||||
|
||||
|
||||
static int
|
||||
quoteprefix(Line *t)
|
||||
{
|
||||
if ( T(t->text)[0] != '>' )
|
||||
return 0;
|
||||
|
||||
return ( T(t->text)[1] == ' ' ) ? 2 : 1;
|
||||
}
|
||||
|
||||
|
||||
static Line *
|
||||
quoteblock(Paragraph *p)
|
||||
{
|
||||
Line *t, *blank, *last = 0;
|
||||
int qp;
|
||||
|
||||
for ( t = p->text; t ; t = t->next ) {
|
||||
if ( last && blankline(t) ) {
|
||||
blank = last;
|
||||
t = skipempty(t);
|
||||
|
||||
if ( !isquote(t) ) {
|
||||
blank->next = 0;
|
||||
return t;
|
||||
}
|
||||
last = blank;
|
||||
}
|
||||
else
|
||||
last = t;
|
||||
|
||||
if ( (qp = quoteprefix(t)) > 0 ) {
|
||||
CLIP(t->text, 0, qp);
|
||||
t->dle = firstnonblank(t);
|
||||
}
|
||||
}
|
||||
return t;
|
||||
}
|
||||
|
||||
|
||||
static Line *
|
||||
listblock(Paragraph *p, int trim)
|
||||
{
|
||||
Line *t = p->text;
|
||||
Line *first = t, *blank, *last = 0;
|
||||
|
||||
do {
|
||||
if ( last ) {
|
||||
if ( islist(t, &trim) ) {
|
||||
last->next = 0;
|
||||
return t;
|
||||
}
|
||||
else if ( blankline(t) ) {
|
||||
last = t;
|
||||
t = skipempty(t);
|
||||
|
||||
if ( (t == 0) || (t->dle < 4) ) {
|
||||
last->next = 0;
|
||||
return t;
|
||||
}
|
||||
}
|
||||
else {
|
||||
last = t;
|
||||
t = t->next;
|
||||
}
|
||||
}
|
||||
else {
|
||||
last = t;
|
||||
t = t->next;
|
||||
}
|
||||
CLIP(last->text,0,trim);
|
||||
last->dle = firstnonblank(last);
|
||||
|
||||
if ( t ) trim = (t->dle < 4) ? t->dle : 4;
|
||||
} while ( t );
|
||||
return t;
|
||||
}
|
||||
|
||||
|
||||
static int
|
||||
tgood(char c)
|
||||
{
|
||||
switch (c) {
|
||||
case '\'':
|
||||
case '"': return c;
|
||||
case '(': return ')';
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* add a new (image or link) footnote to the footnote table
|
||||
*/
|
||||
static Line*
|
||||
addfootnote(Line *p)
|
||||
{
|
||||
int j, i;
|
||||
int c;
|
||||
Line *p2 = p->next;
|
||||
|
||||
Footnote *foot = &EXPAND(footnotes);
|
||||
|
||||
CREATE(foot->tag);
|
||||
CREATE(foot->link);
|
||||
CREATE(foot->title);
|
||||
foot->height = foot->width = 0;
|
||||
|
||||
for (j=i=p->dle; T(p->text)[j] != ']'; j++)
|
||||
EXPAND(foot->tag) = T(p->text)[j];
|
||||
|
||||
EXPAND(foot->tag) = T(p->text)[j++];
|
||||
j = nextnonblank(p, j+1);
|
||||
|
||||
while ( (j < S(p->text)) && !isspace(T(p->text)[j]) )
|
||||
EXPAND(foot->link) = T(p->text)[j++];
|
||||
j = nextnonblank(p,j);
|
||||
|
||||
if ( T(p->text)[j] == '=' ) {
|
||||
sscanf(T(p->text)+j, "=%dx%d", &foot->width, &foot->height);
|
||||
while ( (j < S(p->text)) && !isspace(T(p->text)[j]) )
|
||||
++j;
|
||||
j = nextnonblank(p,j);
|
||||
}
|
||||
|
||||
|
||||
if ( (j >= S(p->text)) && p2 && p2->dle && tgood(T(p2->text)[p2->dle]) ) {
|
||||
j = p2->dle;
|
||||
p = p2;
|
||||
}
|
||||
|
||||
if ( (c = tgood(T(p->text)[j])) )
|
||||
while ( (j < S(p->text)-1) && (T(p->text)[++j] != c) )
|
||||
EXPAND(foot->title) = T(p->text)[j];
|
||||
|
||||
return p->next;
|
||||
}
|
||||
|
||||
|
||||
typedef ANCHOR(Paragraph) Document;
|
||||
|
||||
|
||||
/*
|
||||
* allocate a paragraph header, link it to the
|
||||
* tail of the current document
|
||||
*/
|
||||
static Paragraph *
|
||||
Pp(Document *d, Line *ptr, int typ, int para)
|
||||
{
|
||||
Paragraph *ret = calloc(sizeof *ret, 1);
|
||||
|
||||
ret->text = ptr;
|
||||
ret->typ = typ;
|
||||
ret->para = para;
|
||||
ret->align = LEFT;
|
||||
|
||||
return ATTACH(*d, ret);
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* break a collection of markdown input into
|
||||
* blocks of lists, code, html, and text to
|
||||
* be marked up.
|
||||
*/
|
||||
static Paragraph *
|
||||
compile(Line *ptr, int toplevel)
|
||||
{
|
||||
Document d = { 0, 0 };
|
||||
Paragraph *p;
|
||||
char *key;
|
||||
int list_type, indent;
|
||||
|
||||
while ( ptr = skipempty(ptr) ) {
|
||||
if ( toplevel && (key = isopentag(ptr)) ) {
|
||||
p = Pp(&d, ptr, HTML, 0);
|
||||
ptr = htmlblock(p, key);
|
||||
}
|
||||
else if ( iscode(ptr) ) {
|
||||
p = Pp(&d, ptr, CODE, 0);
|
||||
ptr = codeblock(p);
|
||||
}
|
||||
else if ( ishr(ptr) ) {
|
||||
p = Pp(&d, 0, HR, 0);
|
||||
ptr = ptr->next;
|
||||
}
|
||||
else if ( list_type = islist(ptr, &indent) ) {
|
||||
p = Pp(&d, ptr, list_type, 0);
|
||||
ptr = listblock(p, indent);
|
||||
|
||||
p->down = compile(p->text, 0);
|
||||
}
|
||||
else if ( isquote(ptr) ) {
|
||||
p = Pp(&d, ptr, QUOTE, 0);
|
||||
ptr = quoteblock(p);
|
||||
p->down = compile(p->text, 0);
|
||||
}
|
||||
else if ( toplevel && (isfootnote(ptr)) ) {
|
||||
ptr = addfootnote(ptr);
|
||||
continue;
|
||||
}
|
||||
else {
|
||||
p = Pp(&d, ptr, MARKUP, toplevel);
|
||||
ptr = textblock(p);
|
||||
}
|
||||
}
|
||||
return T(d);
|
||||
}
|
||||
|
||||
|
||||
static void
|
||||
freeLine(Line *p)
|
||||
{
|
||||
if (p->next) freeLine(p->next);
|
||||
free(T(p->text));
|
||||
free(p);
|
||||
}
|
||||
|
||||
|
||||
static void
|
||||
freeParagraph(Paragraph *p)
|
||||
{
|
||||
Line *t;
|
||||
|
||||
if (p->next) freeParagraph(p->next);
|
||||
if (p->down) freeParagraph(p->down);
|
||||
else if (p->text) freeLine(p->text);
|
||||
free(p);
|
||||
}
|
||||
|
||||
|
||||
static void
|
||||
freefootnotes()
|
||||
{
|
||||
int i;
|
||||
|
||||
for (i=0; i < S(footnotes); i++) {
|
||||
free(T(T(footnotes)[i].tag));
|
||||
free(T(T(footnotes)[i].link));
|
||||
free(T(T(footnotes)[i].title));
|
||||
}
|
||||
S(footnotes) = 0;
|
||||
}
|
||||
|
||||
|
||||
static void
|
||||
initmarkdown()
|
||||
{
|
||||
static int init = 0;
|
||||
|
||||
if ( init ) return;
|
||||
|
||||
srandom((unsigned int)time(0));
|
||||
qsort(blocktags, SZBLOCKTAGS, sizeof blocktags[0], casort);
|
||||
CREATE(footnotes);
|
||||
CREATE(output);
|
||||
init = 1;
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
markdown(Line *text)
|
||||
{
|
||||
Paragraph *paragraph;
|
||||
initmarkdown();
|
||||
|
||||
paragraph = compile(text, 1);
|
||||
qsort(T(footnotes), S(footnotes), sizeof T(footnotes)[0], footsort);
|
||||
|
||||
emit(paragraph);
|
||||
|
||||
freefootnotes();
|
||||
freeParagraph(paragraph);
|
||||
}
|
||||
|
||||
|
||||
#if PROGRAM
|
||||
main(int argc, char **argv)
|
||||
{
|
||||
|
||||
if ( (argc > 1) && !freopen(argv[1], "r", stdin) ) {
|
||||
perror(argv[1]);
|
||||
exit(1);
|
||||
}
|
||||
markdown(in(stdin));
|
||||
exit(0);
|
||||
}
|
||||
#endif
|
||||
Reference in New Issue
Block a user