/* $Id: hash.c,v 1.26 2005/05/08 04:32:44 reinelt Exp $ * * hashes (associative arrays) * * Copyright (C) 2003 Michael Reinelt * Copyright (C) 2004 The LCD4Linux Team * * This file is part of LCD4Linux. * * LCD4Linux 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. * * LCD4Linux 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., 675 Mass Ave, Cambridge, MA 02139, USA. * * * $Log: hash.c,v $ * Revision 1.26 2005/05/08 04:32:44 reinelt * CodingStyle added and applied * * Revision 1.25 2005/01/18 06:30:23 reinelt * added (C) to all copyright statements * * Revision 1.24 2004/06/26 12:04:59 reinelt * * uh-oh... the last CVS log message messed up things a lot... * * Revision 1.23 2004/06/26 09:27:21 reinelt * * added '-W' to CFLAGS * changed all C++ comments to C ones * cleaned up a lot of signed/unsigned mistakes * * Revision 1.22 2004/06/20 10:09:56 reinelt * * 'const'ified the whole source * * Revision 1.21 2004/06/17 06:23:43 reinelt * * hash handling rewritten to solve performance issues * * Revision 1.20 2004/06/13 01:12:52 reinelt * * debug widgets changed (thanks to Andy Baxter) * * Revision 1.19 2004/06/01 06:45:30 reinelt * * some Fixme's processed * documented some code * * Revision 1.18 2004/05/31 16:39:06 reinelt * * added NULL display driver (for debugging/profiling purposes) * added backlight/contrast initialisation for matrixOrbital * added Backlight initialisation for Cwlinux * * Revision 1.17 2004/03/11 06:39:59 reinelt * big patch from Martin: * - reuse filehandles * - memory leaks fixed * - earlier busy-flag checking with HD44780 * - reuse memory for strings in RESULT and hash * - netdev_fast to wavid time-consuming regex * * Revision 1.16 2004/03/03 08:40:07 hejl * Fixed memory leak in hash_get_regex * * Revision 1.15 2004/03/03 04:44:16 reinelt * changes (cosmetics?) to the big patch from Martin * hash patch un-applied * * Revision 1.14 2004/03/03 03:47:04 reinelt * big patch from Martin Hejl: * - use qprintf() where appropriate * - save CPU cycles on gettimeofday() * - add quit() functions to free allocated memory * - fixed lots of memory leaks * * Revision 1.13 2004/02/27 06:07:55 reinelt * hash improvements from Martin * * Revision 1.12 2004/01/30 20:57:56 reinelt * HD44780 patch from Martin Hejl * dmalloc integrated * * Revision 1.11 2004/01/29 04:40:02 reinelt * every .c file includes "config.h" now * * Revision 1.10 2004/01/27 04:48:57 reinelt * bug with hash_age() fixed (thanks to Markus Keil for pointing this out) * * Revision 1.9 2004/01/22 07:57:45 reinelt * several bugs fixed where segfaulting on layout>display * Crystalfontz driver optimized, 632 display already works * * Revision 1.8 2004/01/21 14:29:03 reinelt * new helper 'hash_get_regex' which delivers the sum over regex matched items * new function 'disk()' which uses this regex matching * * Revision 1.7 2004/01/21 10:48:17 reinelt * hash_age function added * * Revision 1.6 2004/01/20 05:36:59 reinelt * moved text-display-specific stuff to drv_generic_text * moved all the bar stuff from drv_generic_bar to generic_text * * Revision 1.5 2004/01/18 09:01:45 reinelt * /proc/stat parsing finished * * Revision 1.4 2004/01/18 06:54:08 reinelt * bug in expr.c fixed (thanks to Xavier) * some progress with /proc/stat parsing * * Revision 1.3 2004/01/16 07:26:25 reinelt * moved various /proc parsing to own functions * made some progress with /proc/stat parsing * * Revision 1.2 2004/01/16 05:04:53 reinelt * started plugin proc_stat which should parse /proc/stat * which again is a paint in the a** * thinking over implementation methods of delta functions * (CPU load, ...) * * Revision 1.1 2004/01/13 10:03:01 reinelt * new util 'hash' for associative arrays * new plugin 'cpuinfo' * */ /* * exported functions: * * void hash_create (HASH *Hash); * initializes hash * * int hash_age (HASH *Hash, char *key, char **value); * return time of last hash_put * * void hash_put (HASH *Hash, char *key, char *val); * set an entry in the hash * * void hash_put_delta (HASH *Hash, char *key, char *val); * set a delta entry in the hash * * char *hash_get (HASH *Hash, char *key); * fetch an entry from the hash * * double hash_get_delta (HASH *Hash, char *key, int delay); * fetch a delta antry from the hash * * double hash_get_regex (HASH *Hash, char *key, int delay); * fetch one or more entries from the hash * * void hash_destroy (HASH *Hash); * releases hash * */ #include "config.h" #include #include #include #include #include "debug.h" #include "hash.h" #ifdef WITH_DMALLOC #include #endif /* number of slots for delta processing */ #define DELTA_SLOTS 64 /* string buffer chunk size */ #define CHUNK_SIZE 16 /* initialize a new hash table */ void hash_create(HASH * Hash) { Hash->sorted = 0; Hash->timestamp.tv_sec = 0; Hash->timestamp.tv_usec = 0; Hash->nItems = 0; Hash->Items = NULL; Hash->nColumns = 0; Hash->Columns = NULL; Hash->delimiter = strdup(" \t\n"); } /* bsearch compare function for hash items */ static int hash_lookup_item(const void *a, const void *b) { char *key = (char *) a; HASH_ITEM *item = (HASH_ITEM *) b; return strcasecmp(key, item->key); } /* qsort compare function for hash items */ static int hash_sort_item(const void *a, const void *b) { HASH_ITEM *ha = (HASH_ITEM *) a; HASH_ITEM *hb = (HASH_ITEM *) b; return strcasecmp(ha->key, hb->key); } /* bsearch compare function for hash headers */ static int hash_lookup_column(const void *a, const void *b) { char *key = (char *) a; HASH_COLUMN *column = (HASH_COLUMN *) b; return strcasecmp(key, column->key); } /* qsort compare function for hash headers */ static int hash_sort_column(const void *a, const void *b) { HASH_COLUMN *ha = (HASH_COLUMN *) a; HASH_COLUMN *hb = (HASH_COLUMN *) b; return strcasecmp(ha->key, hb->key); } /* split a value into columns and */ /* return the nth column in a string */ /* WARNING: does return a pointer to a static string!! */ static char *split(const char *val, const int column, const char *delimiter) { static char buffer[256]; int num; size_t len; const char *beg, *end; if (column < 0) return (char *) val; if (val == NULL) return NULL; num = 0; len = 0; beg = val; end = beg; while (beg && *beg) { while (strchr(delimiter, *beg)) beg++; end = strpbrk(beg, delimiter); if (num++ == column) break; beg = end ? end + 1 : NULL; } if (beg != NULL) { len = end ? (size_t) (end - beg) : strlen(beg); if (len >= sizeof(buffer)) len = sizeof(buffer) - 1; strncpy(buffer, beg, len); } buffer[len] = '\0'; return buffer; } /* search an entry in the hash table: */ /* If the table is flagged "sorted", the entry is looked */ /* up using the bsearch function. If the table is */ /* unsorted, it will be searched in a linear way */ static HASH_ITEM *hash_lookup(HASH * Hash, const char *key, const int do_sort) { HASH_ITEM *Item = NULL; /* maybe sort the array */ if (do_sort && !Hash->sorted) { qsort(Hash->Items, Hash->nItems, sizeof(HASH_ITEM), hash_sort_item); Hash->sorted = 1; } /* no key was passed */ if (key == NULL) return NULL; /* lookup using bsearch */ if (Hash->sorted) { Item = bsearch(key, Hash->Items, Hash->nItems, sizeof(HASH_ITEM), hash_lookup_item); } /* linear search */ if (Item == NULL) { int i; for (i = 0; i < Hash->nItems; i++) { if (strcmp(key, Hash->Items[i].key) == 0) { Item = &(Hash->Items[i]); break; } } } return Item; } /* return the age in milliseconds of an entry from the hash table */ /* or from the hash table itself if key is NULL */ /* returns -1 if entry does not exist */ int hash_age(HASH * Hash, const char *key) { HASH_ITEM *Item; struct timeval now, *timestamp; if (key == NULL) { timestamp = &(Hash->timestamp); } else { Item = hash_lookup(Hash, key, 1); if (Item == NULL) return -1; timestamp = &(Item->Slot[Item->index].timestamp); } gettimeofday(&now, NULL); return (now.tv_sec - timestamp->tv_sec) * 1000 + (now.tv_usec - timestamp->tv_usec) / 1000; } /* add an entry to the column header table */ void hash_set_column(HASH * Hash, const int number, const char *column) { if (Hash == NULL) return; Hash->nColumns++; Hash->Columns = realloc(Hash->Columns, Hash->nColumns * sizeof(HASH_COLUMN)); Hash->Columns[Hash->nColumns - 1].key = strdup(column); Hash->Columns[Hash->nColumns - 1].val = number; qsort(Hash->Columns, Hash->nColumns, sizeof(HASH_COLUMN), hash_sort_column); } /* fetch a column number by column header */ static int hash_get_column(HASH * Hash, const char *key) { HASH_COLUMN *Column; if (key == NULL || *key == '\0') return -1; Column = bsearch(key, Hash->Columns, Hash->nColumns, sizeof(HASH_COLUMN), hash_lookup_column); if (Column == NULL) return -1; return Column->val; } /* set column delimiters */ void hash_set_delimiter(HASH * Hash, const char *delimiter) { if (Hash->delimiter != NULL) free(Hash->delimiter); Hash->delimiter = strdup(delimiter); } /* get a string from the hash table */ char *hash_get(HASH * Hash, const char *key, const char *column) { HASH_ITEM *Item; int c; Item = hash_lookup(Hash, key, 1); if (Item == NULL) return NULL; c = hash_get_column(Hash, column); return split(Item->Slot[Item->index].value, c, Hash->delimiter); } /* get a delta value from the delta table */ double hash_get_delta(HASH * Hash, const char *key, const char *column, const int delay) { HASH_ITEM *Item; HASH_SLOT *Slot1, *Slot2; int i, c; double v1, v2; double dv, dt; struct timeval now, end; /* lookup item */ Item = hash_lookup(Hash, key, 1); if (Item == NULL) return 0.0; /* this is the "current" Slot */ Slot1 = &(Item->Slot[Item->index]); /* fetch column number */ c = hash_get_column(Hash, column); /* if delay is zero, return absolute value */ if (delay == 0) return atof(split(Slot1->value, c, Hash->delimiter)); /* prepare timing values */ now = Slot1->timestamp; end.tv_sec = now.tv_sec; end.tv_usec = now.tv_usec - 1000 * delay; while (end.tv_usec < 0) { end.tv_sec--; end.tv_usec += 1000000; } /* search delta slot */ Slot2 = &(Item->Slot[Item->index]); for (i = 1; i < Item->nSlot; i++) { Slot2 = &(Item->Slot[(Item->index + i) % Item->nSlot]); if (Slot2->timestamp.tv_sec == 0) break; if (timercmp(&(Slot2->timestamp), &end, <)) break; } /* empty slot => try the one before */ if (Slot2->timestamp.tv_sec == 0) { i--; Slot2 = &(Item->Slot[(Item->index + i) % Item->nSlot]); } /* not enough slots available... */ if (i == 0) return 0.0; /* delta value, delta time */ v1 = atof(split(Slot1->value, c, Hash->delimiter)); v2 = atof(split(Slot2->value, c, Hash->delimiter)); dv = v1 - v2; dt = (Slot1->timestamp.tv_sec - Slot2->timestamp.tv_sec) + (Slot1->timestamp.tv_usec - Slot2->timestamp.tv_usec) / 1000000.0; if (dt > 0.0 && dv >= 0.0) return dv / dt; return 0.0; } /* get a delta value from the delta table */ /* key may contain regular expressions, and the sum */ /* of all matching entries is returned. */ double hash_get_regex(HASH * Hash, const char *key, const char *column, const int delay) { double sum; regex_t preg; int i, err; err = regcomp(&preg, key, REG_ICASE | REG_NOSUB); if (err != 0) { char buffer[32]; regerror(err, &preg, buffer, sizeof(buffer)); error("error in regular expression: %s", buffer); regfree(&preg); return 0.0; } /* force the table to be sorted by requesting anything */ hash_lookup(Hash, NULL, 1); sum = 0.0; for (i = 0; i < Hash->nItems; i++) { if (regexec(&preg, Hash->Items[i].key, 0, NULL, 0) == 0) { sum += hash_get_delta(Hash, Hash->Items[i].key, column, delay); } } regfree(&preg); return sum; } /* insert a key/val pair into the hash table */ /* If the entry does already exist, it will be overwritten, */ /* and the table stays sorted (if it has been before). */ /* Otherwise, the entry is appended at the end, and */ /* the table will be flagged 'unsorted' afterwards */ static HASH_ITEM *hash_set(HASH * Hash, const char *key, const char *value, const int delta) { HASH_ITEM *Item; HASH_SLOT *Slot; int size; Item = hash_lookup(Hash, key, 0); if (Item == NULL) { /* add entry */ Hash->sorted = 0; Hash->nItems++; Hash->Items = realloc(Hash->Items, Hash->nItems * sizeof(HASH_ITEM)); Item = &(Hash->Items[Hash->nItems - 1]); Item->key = strdup(key); Item->index = 0; Item->nSlot = delta; Item->Slot = malloc(Item->nSlot * sizeof(HASH_SLOT)); memset(Item->Slot, 0, Item->nSlot * sizeof(HASH_SLOT)); } else { /* maybe enlarge delta table */ if (Item->nSlot < delta) { Item->nSlot = delta; Item->Slot = realloc(Item->Slot, Item->nSlot * sizeof(HASH_SLOT)); } } if (Item->nSlot > 1) { /* move the pointer to the next free slot, wrap around if necessary */ if (--Item->index < 0) Item->index = Item->nSlot - 1; } /* create entry */ Slot = &(Item->Slot[Item->index]); size = strlen(value) + 1; /* maybe enlarge value buffer */ if (size > Slot->size) { /* buffer is either empty or too small */ /* allocate memory in multiples of CHUNK_SIZE */ Slot->size = CHUNK_SIZE * (size / CHUNK_SIZE + 1); Slot->value = realloc(Slot->value, Slot->size); } /* set value */ strcpy(Slot->value, value); /* set timestamps */ gettimeofday(&(Hash->timestamp), NULL); Slot->timestamp = Hash->timestamp; return Item; } /* insert a string into the hash table */ /* without delta processing */ void hash_put(HASH * Hash, const char *key, const char *value) { hash_set(Hash, key, value, 1); } /* insert a string into the hash table */ /* with delta processing */ void hash_put_delta(HASH * Hash, const char *key, const char *value) { hash_set(Hash, key, value, DELTA_SLOTS); } void hash_destroy(HASH * Hash) { int i; if (Hash->Items) { /* free all headers */ for (i = 0; i < Hash->nColumns; i++) { if (Hash->Columns[i].key) free(Hash->Columns[i].key); } /* free header table */ free(Hash->Columns); /* free all items */ for (i = 0; i < Hash->nItems; i++) { if (Hash->Items[i].key) free(Hash->Items[i].key); if (Hash->Items[i].Slot) free(Hash->Items[i].Slot); } /* free items table */ free(Hash->Items); } Hash->sorted = 0; Hash->nItems = 0; Hash->Items = NULL; } } /* Comment.Special */ .highlight .gd { color: #000000; background-color: #ffdddd } /* Generic.Deleted */ .highlight .ge { font-style: italic } /* Generic.Emph */ .highlight .gr { color: #aa0000 } /* Generic.Error */ .highlight .gh { color: #333333 } /* Generic.Heading */ .highlight .gi { color: #000000; background-color: #ddffdd } /* Generic.Inserted */ .highlight .go { color: #888888 } /* Generic.Output */ .highlight .gp { color: #555555 } /* Generic.Prompt */ .highlight .gs { font-weight: bold } /* Generic.Strong */ .highlight .gu { color: #666666 } /* Generic.Subheading */ .highlight .gt { color: #aa0000 } /* Generic.Traceback */ .highlight .kc { color: #008800; font-weight: bold } /* Keyword.Constant */ .highlight .kd { color: #008800; font-weight: bold } /* Keyword.Declaration */ .highlight .kn { color: #008800; font-weight: bold } /* Keyword.Namespace */ .highlight .kp { color: #008800 } /* Keyword.Pseudo */ .highlight .kr { color: #008800; font-weight: bold } /* Keyword.Reserved */ .highlight .kt { color: #888888; font-weight: bold } /* Keyword.Type */ .highlight .m { color: #0000DD; font-weight: bold } /* Literal.Number */ .highlight .s { color: #dd2200; background-color: #fff0f0 } /* Literal.String */ .highlight .na { color: #336699 } /* Name.Attribute */ .highlight .nb { color: #003388 } /* Name.Builtin */ .highlight .nc { color: #bb0066; font-weight: bold } /* Name.Class */ .highlight .no { color: #003366; font-weight: bold } /* Name.Constant */ .highlight .nd { color: #555555 } /* Name.Decorator */ .highlight .ne { color: #bb0066; font-weight: bold } /* Name.Exception */ .highlight .nf { color: #0066bb; font-weight: bold } /* Name.Function */ .highlight .nl { color: #336699; font-style: italic } /* Name.Label */ .highlight .nn { color: #bb0066; font-weight: bold } /* Name.Namespace */ .highlight .py { color: #336699; font-weight: bold } /* Name.Property */ .highlight .nt { color: #bb0066; font-weight: bold } /* Name.Tag */ .highlight .nv { color: #336699 } /* Name.Variable */ .highlight .ow { color: #008800 } /* Operator.Word */ .highlight .w { color: #bbbbbb } /* Text.Whitespace */ .highlight .mb { color: #0000DD; font-weight: bold } /* Literal.Number.Bin */ .highlight .mf { color: #0000DD; font-weight: bold } /* Literal.Number.Float */ .highlight .mh { color: #0000DD; font-weight: bold } /* Literal.Number.Hex */ .highlight .mi { color: #0000DD; font-weight: bold } /* Literal.Number.Integer */ .highlight .mo { color: #0000DD; font-weight: bold } /* Literal.Number.Oct */ .highlight .sa { color: #dd2200; background-color: #fff0f0 } /* Literal.String.Affix */ .highlight .sb { color: #dd2200; background-color: #fff0f0 } /* Literal.String.Backtick */ .highlight .sc { color: #dd2200; background-color: #fff0f0 } /* Literal.String.Char */ .highlight .dl { color: #dd2200; background-color: #fff0f0 } /* Literal.String.Delimiter */ .highlight .sd { color: #dd2200; background-color: #fff0f0 } /* Literal.String.Doc */ .highlight .s2 { color: #dd2200; background-color: #fff0f0 } /* Literal.String.Double */ .highlight .se { color: #0044dd; background-color: #fff0f0 } /* Literal.String.Escape */ .highlight .sh { color: #dd2200; background-color: #fff0f0 } /* Literal.String.Heredoc */ .highlight .si { color: #3333bb; background-color: #fff0f0 } /* Literal.String.Interpol */ .highlight .sx { color: #22bb22; background-color: #f0fff0 } /* Literal.String.Other */ .highlight .sr { color: #008800; background-color: #fff0ff } /* Literal.String.Regex */ .highlight .s1 { color: #dd2200; background-color: #fff0f0 } /* Literal.String.Single */ .highlight .ss { color: #aa6600; background-color: #fff0f0 } /* Literal.String.Symbol */ .highlight .bp { color: #003388 } /* Name.Builtin.Pseudo */ .highlight .fm { color: #0066bb; font-weight: bold } /* Name.Function.Magic */ .highlight .vc { color: #336699 } /* Name.Variable.Class */ .highlight .vg { color: #dd7700 } /* Name.Variable.Global */ .highlight .vi { color: #3333bb } /* Name.Variable.Instance */ .highlight .vm { color: #336699 } /* Name.Variable.Magic */ .highlight .il { color: #0000DD; font-weight: bold } /* Literal.Number.Integer.Long */
#! /bin/sh
# Common stub for a few missing GNU programs while installing.

scriptversion=2005-06-08.21

# Copyright (C) 1996, 1997, 1999, 2000, 2002, 2003, 2004, 2005
#   Free Software Foundation, Inc.
# Originally by Fran,cois Pinard <pinard@iro.umontreal.ca>, 1996.

# 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., 51 Franklin Street, Fifth Floor, Boston, MA
# 02110-1301, USA.

# As a special exception to the GNU General Public License, if you
# distribute this file as part of a program that contains a
# configuration script generated by Autoconf, you may include it under
# the same distribution terms that you use for the rest of that program.

if test $# -eq 0; then
  echo 1>&2 "Try \`$0 --help' for more information"
  exit 1
fi

run=:

# In the cases where this matters, `missing' is being run in the
# srcdir already.
if test -f configure.ac; then
  configure_ac=configure.ac
else
  configure_ac=configure.in
fi

msg="missing on your system"

case "$1" in
--run)
  # Try to run requested program, and just exit if it succeeds.
  run=
  shift
  "$@" && exit 0
  # Exit code 63 means version mismatch.  This often happens
  # when the user try to use an ancient version of a tool on
  # a file that requires a minimum version.  In this case we
  # we should proceed has if the program had been absent, or
  # if --run hadn't been passed.
  if test $? = 63; then
    run=:
    msg="probably too old"
  fi
  ;;

  -h|--h|--he|--hel|--help)
    echo "\
$0 [OPTION]... PROGRAM [ARGUMENT]...

Handle \`PROGRAM [ARGUMENT]...' for when PROGRAM is missing, or return an
error status if there is no known handling for PROGRAM.

Options:
  -h, --help      display this help and exit
  -v, --version   output version information and exit
  --run           try to run the given command, and emulate it if it fails

Supported PROGRAM values:
  aclocal      touch file \`aclocal.m4'
  autoconf     touch file \`configure'
  autoheader   touch file \`config.h.in'
  automake     touch all \`Makefile.in' files
  bison        create \`y.tab.[ch]', if possible, from existing .[ch]
  flex         create \`lex.yy.c', if possible, from existing .c
  help2man     touch the output file
  lex          create \`lex.yy.c', if possible, from existing .c
  makeinfo     touch the output file
  tar          try tar, gnutar, gtar, then tar without non-portable flags
  yacc         create \`y.tab.[ch]', if possible, from existing .[ch]

Send bug reports to <bug-automake@gnu.org>."
    exit $?
    ;;

  -v|--v|--ve|--ver|--vers|--versi|--versio|--version)
    echo "missing $scriptversion (GNU Automake)"
    exit $?
    ;;

  -*)
    echo 1>&2 "$0: Unknown \`$1' option"
    echo 1>&2 "Try \`$0 --help' for more information"
    exit 1
    ;;

esac

# Now exit if we have it, but it failed.  Also exit now if we
# don't have it and --version was passed (most likely to detect
# the program).
case "$1" in
  lex|yacc)
    # Not GNU programs, they don't have --version.
    ;;

  tar)
    if test -n "$run"; then
       echo 1>&2 "ERROR: \`tar' requires --run"
       exit 1
    elif test "x$2" = "x--version" || test "x$2" = "x--help"; then
       exit 1
    fi
    ;;

  *)
    if test -z "$run" && ($1 --version) > /dev/null 2>&1; then
       # We have it, but it failed.
       exit 1
    elif test "x$2" = "x--version" || test "x$2" = "x--help"; then
       # Could not run --version or --help.  This is probably someone
       # running `$TOOL --version' or `$TOOL --help' to check whether
       # $TOOL exists and not knowing $TOOL uses missing.
       exit 1
    fi
    ;;
esac

# If it does not exist, or fails to run (possibly an outdated version),
# try to emulate it.
case "$1" in
  aclocal*)
    echo 1>&2 "\
WARNING: \`$1' is $msg.  You should only need it if
         you modified \`acinclude.m4' or \`${configure_ac}'.  You might want
         to install the \`Automake' and \`Perl' packages.  Grab them from
         any GNU archive site."
    touch aclocal.m4
    ;;

  autoconf)
    echo 1>&2 "\
WARNING: \`$1' is $msg.  You should only need it if
         you modified \`${configure_ac}'.  You might want to install the
         \`Autoconf' and \`GNU m4' packages.  Grab them from any GNU
         archive site."
    touch configure
    ;;

  autoheader)
    echo 1>&2 "\
WARNING: \`$1' is $msg.  You should only need it if
         you modified \`acconfig.h' or \`${configure_ac}'.  You might want
         to install the \`Autoconf' and \`GNU m4' packages.  Grab them
         from any GNU archive site."
    files=`sed -n 's/^[ ]*A[CM]_CONFIG_HEADER(\([^)]*\)).*/\1/p' ${configure_ac}`
    test -z "$files" && files="config.h"
    touch_files=
    for f in $files; do
      case "$f" in
      *:*) touch_files="$touch_files "`echo "$f" |
				       sed -e 's/^[^:]*://' -e 's/:.*//'`;;
      *) touch_files="$touch_files $f.in";;
      esac
    done
    touch $touch_files
    ;;

  automake*)
    echo 1>&2 "\
WARNING: \`$1' is $msg.  You should only need it if
         you modified \`Makefile.am', \`acinclude.m4' or \`${configure_ac}'.
         You might want to install the \`Automake' and \`Perl' packages.
         Grab them from any GNU archive site."
    find . -type f -name Makefile.am -print |
	   sed 's/\.am$/.in/' |
	   while read f; do touch "$f"; done
    ;;

  autom4te)
    echo 1>&2 "\
WARNING: \`$1' is needed, but is $msg.
         You might have modified some files without having the
         proper tools for further handling them.
         You can get \`$1' as part of \`Autoconf' from any GNU
         archive site."

    file=`echo "$*" | sed -n 's/.*--output[ =]*\([^ ]*\).*/\1/p'`
    test -z "$file" && file=`echo "$*" | sed -n 's/.*-o[ ]*\([^ ]*\).*/\1/p'`
    if test -f "$file"; then
	touch $file
    else
	test -z "$file" || exec >$file
	echo "#! /bin/sh"
	echo "# Created by GNU Automake missing as a replacement of"
	echo "#  $ $@"
	echo "exit 0"
	chmod +x $file
	exit 1
    fi
    ;;

  bison|yacc)
    echo 1>&2 "\
WARNING: \`$1' $msg.  You should only need it if
         you modified a \`.y' file.  You may need the \`Bison' package
         in order for those modifications to take effect.  You can get
         \`Bison' from any GNU archive site."
    rm -f y.tab.c y.tab.h
    if [ $# -ne 1 ]; then
        eval LASTARG="\${$#}"
	case "$LASTARG" in
	*.y)
	    SRCFILE=`echo "$LASTARG" | sed 's/y$/c/'`
	    if [ -f "$SRCFILE" ]; then
	         cp "$SRCFILE" y.tab.c
	    fi
	    SRCFILE=`echo "$LASTARG" | sed 's/y$/h/'`
	    if [ -f "$SRCFILE" ]; then
	         cp "$SRCFILE" y.tab.h
	    fi
	  ;;
	esac
    fi
    if [ ! -f y.tab.h ]; then
	echo >y.tab.h
    fi
    if [ ! -f y.tab.c ]; then
	echo 'main() { return 0; }' >y.tab.c
    fi
    ;;

  lex|flex)
    echo 1>&2 "\
WARNING: \`$1' is $msg.  You should only need it if
         you modified a \`.l' file.  You may need the \`Flex' package
         in order for those modifications to take effect.  You can get
         \`Flex' from any GNU archive site."
    rm -f lex.yy.c
    if [ $# -ne 1 ]; then
        eval LASTARG="\${$#}"
	case "$LASTARG" in
	*.l)
	    SRCFILE=`echo "$LASTARG" | sed 's/l$/c/'`
	    if [ -f "$SRCFILE" ]; then
	         cp "$SRCFILE" lex.yy.c
	    fi
	  ;;
	esac
    fi
    if [ ! -f lex.yy.c ]; then
	echo 'main() { return 0; }' >lex.yy.c
    fi
    ;;

  help2man)
    echo 1>&2 "\
WARNING: \`$1' is $msg.  You should only need it if
	 you modified a dependency of a manual page.  You may need the
	 \`Help2man' package in order for those modifications to take
	 effect.  You can get \`Help2man' from any GNU archive site."

    file=`echo "$*" | sed -n 's/.*-o \([^ ]*\).*/\1/p'`
    if test -z "$file"; then
	file=`echo "$*" | sed -n 's/.*--output=\([^ ]*\).*/\1/p'`
    fi
    if [ -f "$file" ]; then
	touch $file
    else
	test -z "$file" || exec >$file
	echo ".ab help2man is required to generate this page"
	exit 1
    fi
    ;;

  makeinfo)
    echo 1>&2 "\
WARNING: \`$1' is $msg.  You should only need it if
         you modified a \`.texi' or \`.texinfo' file, or any other file
         indirectly affecting the aspect of the manual.  The spurious
         call might also be the consequence of using a buggy \`make' (AIX,
         DU, IRIX).  You might want to install the \`Texinfo' package or
         the \`GNU make' package.  Grab either from any GNU archive site."
    # The file to touch is that specified with -o ...
    file=`echo "$*" | sed -n 's/.*-o \([^ ]*\).*/\1/p'`
    if test -z "$file"; then
      # ... or it is the one specified with @setfilename ...
      infile=`echo "$*" | sed 's/.* \([^ ]*\) *$/\1/'`
      file=`sed -n '/^@setfilename/ { s/.* \([^ ]*\) *$/\1/; p; q; }' $infile`
      # ... or it is derived from the source name (dir/f.texi becomes f.info)
      test -z "$file" && file=`echo "$infile" | sed 's,.*/,,;s,.[^.]*$,,'`.info
    fi
    # If the file does not exist, the user really needs makeinfo;
    # let's fail without touching anything.
    test -f $file || exit 1
    touch $file
    ;;

  tar)
    shift

    # We have already tried tar in the generic part.
    # Look for gnutar/gtar before invocation to avoid ugly error
    # messages.
    if (gnutar --version > /dev/null 2>&1); then
       gnutar "$@" && exit 0
    fi
    if (gtar --version > /dev/null 2>&1); then
       gtar "$@" && exit 0
    fi
    firstarg="$1"
    if shift; then
	case "$firstarg" in
	*o*)
	    firstarg=`echo "$firstarg" | sed s/o//`
	    tar "$firstarg" "$@" && exit 0
	    ;;
	esac
	case "$firstarg" in
	*h*)
	    firstarg=`echo "$firstarg" | sed s/h//`
	    tar "$firstarg" "$@" && exit 0
	    ;;
	esac
    fi

    echo 1>&2 "\
WARNING: I can't seem to be able to run \`tar' with the given arguments.
         You may want to install GNU tar or Free paxutils, or check the
         command line arguments."
    exit 1
    ;;

  *)
    echo 1>&2 "\
WARNING: \`$1' is needed, and is $msg.
         You might have modified some files without having the
         proper tools for further handling them.  Check the \`README' file,
         it often tells you about the needed prerequisites for installing
         this package.  You may also peek at any GNU archive site, in case
         some other package would contain this missing \`$1' program."
    exit 1
    ;;
esac

exit 0

# Local variables:
# eval: (add-hook 'write-file-hooks 'time-stamp)
# time-stamp-start: "scriptversion="
# time-stamp-format: "%:y-%02m-%02d.%02H"
# time-stamp-end: "$"
# End: