Yeehaa, Yahoo,  Yipee and the like!

Well, there are some significant steps forward since yesterday :)
Gosh, it feels good when m4 finally agrees to do what you wanted to
:-)

I have implemented support for $.@, which is [$1].[$2]. etc. (`.' is
the separator, defaults to comma), and for $.*, which is
smash($1).smash($2). etc., where `.' defaults to `:', and `smash'
singles out all the white spaces.

If you required no tracing format, you get `$f:$l:$n:$*', i.e., for
instance:

  ~fu % ~ace/autotrace -m ~ace --trace AC_DEFINE
  ./aclocal.m4:1694:AC_DEFINE:AFS:1:Define if you have the Andrew File System.
  configure.in:12:AC_DEFINE:_GNU_SOURCE
  configure.in:22:AC_DEFINE:_ALL_SOURCE
  configure.in:23:AC_DEFINE:_POSIX_SOURCE:1:Define if you need to in order for `stat' 
and other things to work.

or even:

~fu % ~ace/autotrace -m ~ace --trace 'AC_OUTPUT:With quotes: $@
without: $*'
With quotes: [Makefile
           doc/Makefile
           intl/Makefile
           lib/Makefile
           man/Makefile
           m4/Makefile
           po/Makefile.in
           src/Makefile
           tests/Makefile
           tests/chmod/Makefile
           tests/cp/Makefile
           tests/dd/Makefile
           tests/dircolors/Makefile
           tests/install/Makefile
           tests/ln/Makefile
           tests/ls/Makefile
           tests/ls-2/Makefile
           tests/mkdir/Makefile
           tests/mv/Makefile
           tests/rm/Makefile
           tests/rmdir/Makefile
           tests/shred/Makefile
           tests/touch/Makefile
          ]
without: Makefile doc/Makefile intl/Makefile lib/Makefile man/Makefile m4/Makefile 
po/Makefile.in src/Makefile tests/Makefile tests/chmod/Makefile tests/cp/Makefile 
tests/dd/Makefile tests/dircolors/Makefile tests/install/Makefile tests/ln/Makefile 
tests/ls/Makefile tests/ls-2/Makefile tests/mkdir/Makefile tests/mv/Makefile 
tests/rm/Makefile tests/rmdir/Makefile tests/shred/Makefile tests/touch/Makefile

worse yet:

  | /tmp % cat foo 
  | define([foo])
  | foo([several
  | 
  | 
  | lines])
  | 
  | foo([a\
  | big\
  | token])
  | /tmp % ~ace/autotrace --trace  foo  -m ~ace foo
  | foo:5:foo:several lines
  | foo:9:foo:abigtoken


Bwahaha :)  So I think we will be able to start using this in
Automake, no?


Well, of course there are problems.  The first one being that if you
trace an m4 builtin, weird things happen.  This can be solved by
undefining them.

        Akim

PS/  Beware there is a literal ^Q in it, which you need if you want
this to work properly.  BTW, is it normal that bash does not split
around ^A?  I found nothing like this in the doc:

  | ~ace % cat -v /tmp/ifs
  | list="a^Qb"
  | IFS="^Q"
  | for i in $list
  | do
  |   echo $i
  | done
  | 
  | list="a^Ab"
  | IFS="^A"
  | for i in $list
  | do
  |   echo $i
  | done

  | ~ace % bash /tmp/ifs
  | /tmp/ifs: /tmp/ifs: cannot execute binary file

Naah, come on, it is not binary!

  | ~ace % cat -v /tmp/ifs
  | #! /bin/sh
  | 
  | list="a^Qb"
  | IFS="^Q"
  | for i in $list
  | do
  |   echo $i
  | done
  | 
  | list="a^Ab"
  | IFS="^A"
  | for i in $list
  | do
  |   echo $i
  | done

  | ~ace % bash /tmp/ifs
  | a
  | b
  | ab

while zsh (with emulate sh) splits it properly.

GNU bash, version 2.04.0(1)-beta5 (i386-pc-linux-gnu)
Copyright 1999 Free Software Foundation, Inc.

#! @SHELL@
# autoconf -- create `configure' using m4 macros
# Copyright (C) 1992, 93, 94, 96, 99, 2000 Free Software Foundation, Inc.

# This program is free software; you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation; either version 2, or (at your option)
# any later version.

# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
# GNU General Public License for more details.

# You should have received a copy of the GNU General Public License
# along with this program; if not, write to the Free Software
# Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
# 02111-1307, USA.

# If given no args, create `configure' from template file `configure.in'.
# With one arg, create a configure script on standard output from
# the given template file.

me=`echo "$0" | sed -e 's,.*/,,'`

usage="\
Usage: autoconf [OPTION] ... [TEMPLATE-FILE]

Generate a configuration script from a TEMPLATE-FILE if given, or
\`configure.in' by default.  Output is sent to the standard output if
TEMPLATE-FILE is given, else into \`configure'.

If the option \`--trace' is used, no configuration script is created.

  -h, --help          print this help, then exit
  -V, --version       print version number, then exit
  -d, --debug         don't remove temporary files
  -m, --macrodir=DIR  directory storing Autoconf's macro files
  -l, --localdir=DIR  directory storing the \`aclocal.m4' file
  -t, --trace=MACRO   report the list of calls to MACRO
  -o, --output=FILE   save output in FILE (stdout is the default)

Report bugs to <[EMAIL PROTECTED]>."

version="\
autoconf (GNU @PACKAGE@) @VERSION@
Written by David J. MacKenzie.

Copyright (C) 1992, 93, 94, 96, 99, 2000 Free Software Foundation, Inc.
This is free software; see the source for copying conditions.  There is NO
warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE."

help="\
Try \`$me --help' for more information."

# NLS nuisances.
# Only set these to C if already set.  These must not be set unconditionally
# because not all systems understand e.g. LANG=C (notably SCO).
# Fixing LC_MESSAGES prevents Solaris sh from translating var values in `set'!
# Non-C LC_CTYPE values break the ctype check.
if test "${LANG+set}"   = set; then LANG=C;   export LANG;   fi
if test "${LC_ALL+set}" = set; then LC_ALL=C; export LC_ALL; fi
if test "${LC_MESSAGES+set}" = set; then LC_MESSAGES=C; export LC_MESSAGES; fi
if test "${LC_CTYPE+set}"    = set; then LC_CTYPE=C;    export LC_CTYPE;    fi

# ac_LF_and_DOT
# We use echo to avoid assuming a particular line-breaking character.
# The extra dot is to prevent the shell from consuming trailing
# line-breaks from the sub-command output.  A line-break within
# single-quotes doesn't work because, if this script is created in a
# platform that uses two characters for line-breaks (e.g., DOS), tr
# would break.
ac_LF_and_DOT=`echo; echo .`

# An uncommon character, used as a separator.
separator=''

# Find GNU m4.
# Handle the case that m4 has moved since we were configured.
# It may have been found originally in a build directory.
: ${M4=@M4@}
case "$M4" in
/*) test -f "$M4" || M4=m4 ;;
esac
# Some non-GNU m4's don't reject the --help option, so give them /dev/null.
case `$M4 --help </dev/null 2>&1` in
*reload-state*);;
*) echo "$me: Autoconf requires GNU m4 1.4 or later" >&2; exit 1 ;;
esac

# Variables.
: ${AC_MACRODIR=@datadir@}
: ${AC_ACLOCALDIR=`(aclocal --print-ac-dir) 2>/dev/null`}
: ${AWK=@AWK@}
debug=false
localdir=
outfile=
# Tasks:
# - trace
#   Trace the first arguments of some macros
# - script
#   Produce the configure script (default)
task=script
: ${TMPDIR=/tmp}
tmpin=$TMPDIR/ac$$.in
tmpout=$TMPDIR/ac$$.out
silent_m4=$TMPDIR/silent$$.m4
trace_m4=$TMPDIR/trace$$.m4
translate_awk=$TMPDIR/trans$$.awk
verbose=:

# Parse command line
while test $# -gt 0 ; do
  case "$1" in
    --version | --vers* | -V )
       echo "$version" ; exit 0 ;;
    --help | --h* | -h )
       echo "$usage"; exit 0 ;;
    -d | --debug | --d* )
         debug=:; shift ;;

    --localdir=* | --l*=* )
       localdir=`echo "$1" | sed -e 's/^[^=]*=//'`
       shift ;;
    --localdir | --l* | -l )
       shift
       test $# -eq 0 && { echo "$help" >&2; exit 1; }
       localdir="$1"
       shift ;;

    --macrodir=* | --m*=* )
       AC_MACRODIR=`echo "$1" | sed -e 's/^[^=]*=//'`
       shift ;;
    --macrodir | --m* | -m )
       shift
       test $# -eq 0 && { echo "$help" >&2; exit 1; }
       AC_MACRODIR="$1"
       shift ;;

    --install )
       task=install
       shift;;

    --verbose | --verb* )
       verbose=echo
       shift;;

    --trace | -t )
       task=trace
       shift
       traces="$traces$separator$1"
       shift ;;
    --trace=* )
       task=trace
       traces="$traces$separator"`echo "$1" | sed -e 's/^[^=]*=//;s/:.*//'`
       shift ;;

    --output | -o )
       shift
       outfile="$1"
       shift ;;
    --output=* )
       outfile=`echo "$1" | sed -e 's/^[^=]*=//'`
       shift ;;

    -- )     # Stop option processing
       shift; break ;;
    - ) # Use stdin as input.
       break ;;
    -* )
       exec >&2
       echo "$me: invalid option $1"
       echo "$help"
       exit 1 ;;
    * )
       break ;;
  esac
done

# Running m4.
if test -n "$localdir"; then
  use_localdir="-I$localdir -DAC_LOCALDIR=$localdir"
fi
run_m4="$M4 --reload $AC_MACRODIR/autoconf.m4f $use_localdir"


case $# in
  0) infile=configure.in
     test $task = script && test "x$outfile" = x && outfile=configure;;
  1) infile="$1" ;;
  *) exec >&2
     echo "$me: invalid number of arguments."
     echo "$help"
     exit 1 ;;
esac

$debug || trap 'rm -f $tmpin $tmpout $silent_m4 $trace_m4' 0 1 2 15
if test z$infile = z-; then
  infile=$tmpin
  cat >$infile
elif test ! -r "$infile"; then
  echo "$me: $infile: No such file or directory" >&2
  exit 1
fi

# Output is produced into FD 4.  Prepare it.
case "x$outfile" in
 x- | x )  # Output to stdout
  exec 4>&1 ;;
 * )
  exec 4>$outfile;;
esac

# Initializations are performed.  Proceed to the main task.
case $task in

  ## --------------------- ##
  ## Generate the script.  ##
  ## --------------------- ##
  script)
  $run_m4 $infile > $tmpout || exit 2

  # You could add your own prefixes to pattern if you wanted to check for
  # them too, e.g. pattern='\(AC_\|ILT_\)', except that UNIX sed doesn't do
  # alternation.
  pattern="A[CHM]_"

  status=0
  if grep "^[^#]*$pattern" $tmpout > /dev/null 2>&1; then
    echo "autoconf: Undefined macros:" >&2
    sed -n "s/^[^#]*\\($pattern[_A-Za-z0-9]*\\).*/\\1/p" $tmpout |
      while read macro; do
        grep -n "^[^#]*$macro" $infile /dev/null
        test $? -eq 1 && echo "***BUG in Autoconf--please report*** $macro"
      done | sort -u >&2
    status=1
  fi

  if test -n "$outfile"; then
    chmod +x $outfile
  fi

  # Put the real line numbers into configure to make config.log more helpful.
  # Because quoting can sometimes get really painful in m4, there are special
  # @tokens@ to substitute.
  sed -e 's/[   ]*$//' <$tmpout |
    sed -e '/^$/N;/\n$/D' |
    $AWK '
      /__oline__/ { printf "%d:", NR + 1 }
                  { print }' |
    sed '
      /__oline__/s/^\([0-9][0-9]*\):\(.*\)__oline__/\2\1/
      s/@BKL@/[/g
      s/@BKR@/]/g
      s/@DLR@/$/g
      s/@PND@/#/g
      ' >&4
  ;; # End of the task script.



  ## -------------- ##
  ## Trace macros.  ##
  ## -------------- ##
  trace)
  # errprint must be silent when we run `m4 --trace', otherwise there can be
  # warnings mixed with traces in m4's stderr.
  cat >$silent_m4 <<\EOF
define(`errprint')dnl
EOF
  # A program to trace m4 macros.
  cat >$trace_m4 <<\EOF
divert(-1)
  changequote([, ])
  define([_at],
         [ifelse([$#], [1], [],
                 [$#], [2], [[[$2]]],
                 [[[$2]][$1]_at([$1], shift(shift($@)))])])
  define([_star],
         [ifelse([$#], [1], [],
                 [$#], [2], [smash([$2])],
                 [smash([$2])[$1]_star([$1], shift(shift($@)))])])
  define([smash],
         [patsubst(patsubst(patsubst(patsubst([[[[$1]]]],
                                     [\\
]),
                            [[
        ]+],
                            [ ]),
                   [^\(..\) ], [\1]),
         [ \(.\)$], [\1])])
  define([args],
         [shift(shift(shift(shift(shift($@)))))])
  define([at],
         [_at([$1], args($@))])
  define([star],
         [_star([$1], args($@))])
EOF
  # A program to translate user tracing requests into m4 macros.
  cat >$translate_awk <<\EOF
BEGIN {
  # File name.
  trans["f"] = "$1";
  # Line number.
  trans["l"] = "$2";
  # Depth.
  trans["d"] = "$3";
  # Name (also available as $0).
  trans["n"] = "$4";
  # Escaped dollar.
  trans["$"] = "$";
  # $@, list of quoted effective arguments.
  trans["@"] = "]at([,], $@)[";
  # $*, list of unquoted effective arguments.
  trans["*"] = "]star([:], $@)[";
}

{
  res = "";

  for (cp = $0; cp; cp = substr(cp, 2))
    {
      char = substr (cp, 1, 1);
      if (char == "$")
        {
          if (match (cp, /^\$[0-9]+/))
            {
              # $n -> $(n + 4)
              res = res "$" (substr (cp, 2, RLENGTH - 1) + 4);
              cp = substr (cp, RLENGTH);
            }
          else if (substr (cp, 2, 1) ~ /[fldn$@*]/)
            {
              res = res trans[substr (cp, 2, 1)];
              cp = substr(cp, 2);
            }
          else if (substr (cp, 3, 1) == "@")
            {
              res = res "]at([" substr (cp, 2, 1)  "], $@)[";
              cp = substr(cp, 3);
            }
          else if (substr (cp, 3, 1) == "*")
            {
              res = res "]star([" substr (cp, 2, 1)  "], $@)[";
              cp = substr(cp, 3);
            }
          else
            {
              print "unrecognized escape: " substr (cp, 1, 2) >"/dev/stderr";
              exit 1
            }
        }
      else
        res = res char;
    }
  print res;
}
EOF
  # Extract both the m4 program and the m4 options from TRACES.
  saved_IFS=$IFS
  IFS=$separator
  for trace in $traces
  do
    test -z "$trace" && continue
    IFS=$saved_IFS
    # The request may have several lines long, hence sed has to quit.
    trace_opt="$trace_opt -t "`echo "$trace" | sed -e 's/:.*//;q'`
    case "$trace" in
      *:*)
        # The `]])' are closing the `define' which is started by sed.
        # This is to cope with multiple line requests.
        echo "$trace]])" |
          sed -e '1s/^\([^:]*\):\(.*\)$/define([AT_\1], [[\2/';;
      *)
        # Default request.
        echo "define([AT_$trace], [[\$f:\$l:\$n:\$*]])";;
    esac |
      $AWK -f $translate_awk >> $trace_m4
  done
  echo "divert(0)dnl" >> $trace_m4

  # Run m4 on the input file to get traces.
  # We don't use the frozen files because we want to redefine `errprint',
  # and because we want to be to trace AC_DEFUN and others.
  $M4 $trace_opt -daflq -I $AC_MACRODIR \
      $silent_m4 autoconf.m4 $infile 2>&1 >/dev/null |
    sed -e 's/^m4trace:\([^:][^:]*\):\([0-9][0-9]*\): -\([0-9][0-9]*\)- 
\([^(][^(]*\)(\(.*\)$/AT_\4([\1], [\2], [\3], [\4], \5/' \
        -e 's/^m4trace:\([^:][^:]*\):\([0-9][0-9]*\): -\([0-9][0-9]*\)- 
\(.*\)$/AT_\4([\1], [\2], [\3], [\4])/' >>$trace_m4

  # Now we are ready to run m4 to process the trace file.
  m4 $trace_m4 >&4
  ;;




  ## -------------------------------------------------------- ##
  ## Task --install.  Install links to the library m4 files.  ##
  ## -------------------------------------------------------- ##
  install)
  # An m4 program that reports what macros are requested, and where
  # they were defined.
  cat >$tmpin <<\EOF
dnl Keep the definition of the old AC_DEFUN
define([AC_DEFUN_OLD], defn([AC_DEFUN]))

dnl Define the macro so that the first time it is expanded, it reports
dnl on stderr its name, and where it was defined.
define([AC_DEFUN],
[AC_DEFUN_OLD([$1],
   [ifdef([AC_DECLARED{$1}],,
          [define([AC_DECLARED{$1}])errprint(]]__file__:__line__:[[ [$1]
)])dnl
][$2])])

dnl All the includes must be disabled.  If they are not, since people don't
dnl protect the first argument of AC_DEFUN, then, if read a second time
dnl this argument will be expanded, and we'll get pure junk out of m4.
define([AC_INCLUDE])
EOF
  # Run m4 with all the library files, save its report on strderr.
  $verbose Running $run_m4 -dipa -t m4_include -t m4_sinclude $tmpin $localdir/*.m4 
$AC_ACLOCALDIR/*.m4 $infile
  $run_m4 -dipa -t m4_include -t m4_sinclude $tmpin $localdir/*.m4 $AC_ACLOCALDIR/*.m4 
$infile >the-script 2>$tmpout
  # Keep only the good lines, there may be other outputs
  grep '^[^: ]*:[0-9][0-9]*:[^:]*$' $tmpout >$tmpin
  # Extract the files that are not in the local dir, and install the links.
  # Save in $tmpout the list of installed links.
  >$tmpout
  $verbose "Required macros:"
  $verbose "`sed -e 's/^/| /' $tmpin`"
  cat $tmpin |
    while read line
    do
      file=`echo "$line" | sed -e 's/:.*//'`
      filename=`echo "$file" | sed -e 's,.*/,,'`
      macro=`echo "$line" | sed -e 's/.*:[      ]*//'`
      if test -f "$file" && test "x$file" != "x$infile"; then
        if test -f $localdir/$filename; then
          $verbose "$filename already installed"
        else
          $verbose "installing $file which provides $macro"
          ln -s "$file" "$localdir/$filename" ||
          cp "$file" "$localdir/$filename" ||
          {
            echo "$me: cannot link from $file to $localdir/$filename" >&2
            exit 1
          }
        fi
        echo "$localdir/$filename" >>$tmpout
      fi
    done
  # Now that we have installed the links, and that we know that the
  # user needs the FILES, check that there is an exact correspondence.
  # Use yourself to get the list of the included files.
  export AC_ACLOCALDIR
  export AC_MACRODIR
  # Not m4_s?include, because it would catch acsite and aclocal, which
  # we don't care of.
  $0 -l "$localdir" -t AC_INCLUDE $inline |
    sed -e 's/^[^:]*:[^:]*:[^:]*://g' |
    sort |
    uniq >$tmpin
  # All the included files are needed.
  for file in `cat $tmpin`;
  do
    if fgrep "$file" $tmpout >/dev/null 2>&1; then :; else
      echo "\`$file' is uselessly included" >&2
    fi
  done
  # All the needed files are included.
  for file in `sort $tmpout | uniq`;
  do
    if fgrep "$file" $tmpin >/dev/null 2>&1; then :; else
      echo "\`$file' is not included" >&2
    fi
  done
  ;;



  ## ------------ ##
  ## Unknown task ##
  ## ------------ ##

  *)echo "$me: internal error: unknown task: $task" >&2
    exit 1
esac

exit $status

Reply via email to