[gnu.emacs.gnus] Fast nnspool-find-article-by-message-id function

jv@mh.nl (Johan Vromans) (03/06/90)

This shar archive contains a fast lookup article by id mechanism for
GNUS using NNSPOOL. It works only if yoy have built NEWS with [n]dbm
or dbz.

Enjoy.

	Johan

#---------------------------------- cut here ----------------------------------
# This is a shell archive.  Remove anything before this line,
# then unpack it by saving it in a file and typing "sh file".
#
# Wrapped by Johan Vromans <jv@mhres> on Mon Mar  5 13:38:39 1990
#
# This archive contains:
#	README		getartbyid.c	getartbyid.el	
#
# Existing files will not be overwritten.
# Error checking via wc(1) will be performed.

LANG=""; export LANG

if test -f README
then
	echo Ok to overwrite existing file README\?
	read answer
	case "$answer" in
	[yY]*)	echo Proceeding;;
	*)	echo Aborting; exit 1;;
	esac
	rm -f README
	if test -f README
	then
		echo Error: could not remove README, aborting
		exit 1
	fi
fi
echo x - README
cat >README <<'@EOF'
This shar archive contains a fast lookup article by id mechanisme for
GNUS using NNSPOOL. It works only if yoy have built NEWS with [n]dbm
or dbz.

It consists of a replacement function for
nnspool-find-article-by-message-id, and a fast lookup program.

The program should be compiled and placed somewher in your PATH.
Compile with:

	gcc -s -O getartbyid.c -o getartbyid -ldbm

It also works with vanilla CC and Jon Zeeff's DBZ.

Load getartbyid.el after loading gnus/nnspool, and you will have a blinding
fast '^' key.

Motivation: I created this function since I could not afford Emacs to
carry an 8Mb buffer all of the time - other programs started running
out of VM.

Enjoy.
@EOF
set `wc -lwc <README`
if test $1$2$3 != 22113680
then
	echo ERROR: wc results of README are $* should be 22 113 680
fi

chmod 644 README

if test -f getartbyid.c
then
	echo Ok to overwrite existing file getartbyid.c\?
	read answer
	case "$answer" in
	[yY]*)	echo Proceeding;;
	*)	echo Aborting; exit 1;;
	esac
	rm -f getartbyid.c
	if test -f getartbyid.c
	then
		echo Error: could not remove getartbyid.c, aborting
		exit 1
	fi
fi
echo x - getartbyid.c
cat >getartbyid.c <<'@EOF'
/* getartinfo.c - fetch article info using Bnews history file */

/* Usage: getartinfo [-v] [id] ... */

#include <stdio.h>
#include <ctype.h>
#include <string.h>

/* DBM / DBZ declarations */

typedef struct { char *dptr; int dsize; } datum;
datum fetch ();

/* other forwards */

char *memcpy ();
static char *lcase ();

#define HISTFILE	"/usr/lib/news/history"
#define BUFLEN	512

int f_verbose = 0;

main (argc, argv)
int argc;
char *argv[];
{
  FILE *hist = NULL;		/* history file, if opened */
  datum key, val;		/* DBM items */
  int fail = 0;			/* failure count */
  char artbuf [BUFLEN];		/* buf to hold article id */
  char *artid;			/* pointer to article id */
  char buf [BUFLEN];		/* read buf for history file */
  long fpos;			/* seek position in hist file */
  char *p;			/*  */

  if (argc >= 1 && !strcmp (argv[1], "-v")) {
    argc--;
    argv++;
    f_verbose = 1;
  }

  /* initialize DBM */
  if (dbminit (HISTFILE) < 0) {
    perror (HISTFILE);
    return -1;
  }

  /* process arguments */
  while (--argc > 0) {

    /* copy article id into article buf, provide < and > if needed */
    strcpy (artid = artbuf+1, *++argv);
    if (*artid != '<') {
      *--artid = '<';
      strcat (artid, ">");
    }

    /* lowcase and build DBM key */
    key.dptr = artid;
    key.dsize = strlen (key.dptr)+1;
    lcase (key.dptr, key.dsize-1);

    /* fetch from DBM */
    val = fetch (key);
    if (val.dptr == NULL) {
      if (f_verbose)
	fprintf (stderr, "%s: not found\n", *argv);
      fail++;			/* tally */
      continue;
    }

    /* open the history file upon first need */
    if (hist == NULL) {
      if ((hist = fopen (HISTFILE, "r")) == NULL) {
	perror (HISTFILE);
	return -1;
      }
    }

    /* get the file pos from the DBM return value */
    memcpy ((char*)&fpos, val.dptr, sizeof(long));

    /* look it up */
    if (fseek (hist, fpos, 0) < 0 ) {
      if (f_verbose)
	perror ("seek");
      fail++;
      continue;
    }
    if (fgets (buf, BUFLEN, hist) == NULL) {
      if (f_verbose)
	perror ("read");
      fail++;
      continue;
    }

    /* check if it is the right article */
    p = strchr (buf, '\t');
    if (p == NULL)
      p = strchr (buf, '\n');
    *p = 0;
    lcase (buf, strlen (buf));
    if (strcmp (buf, key.dptr) != 0) { /* it's not */
      if (f_verbose)
	fprintf (stderr, "db corrupt?\n");
      fail++;
      continue;
    }
    *p = '\t';

    /* print results */
    buf[strlen(buf)-1] = '\0';	/* zap the \n */
    printf ("%s\n", buf);
  }

  /* wrap up */
  dbmclose ();
  if (hist != NULL)
    fclose (hist);

  /* return number of failures */
  return fail;
}

static char *lcase (s)
register char *s;
{
  register int n = strlen (s);
  for (s += n; n > 0; --n) {
    if (isupper(*--s))
      *s = tolower(*s);
  }
  return s;
}
@EOF
set `wc -lwc <getartbyid.c`
if test $1$2$3 != 1354542803
then
	echo ERROR: wc results of getartbyid.c are $* should be 135 454 2803
fi

chmod 644 getartbyid.c

if test -f getartbyid.el
then
	echo Ok to overwrite existing file getartbyid.el\?
	read answer
	case "$answer" in
	[yY]*)	echo Proceeding;;
	*)	echo Aborting; exit 1;;
	esac
	rm -f getartbyid.el
	if test -f getartbyid.el
	then
		echo Error: could not remove getartbyid.el, aborting
		exit 1
	fi
fi
echo x - getartbyid.el
cat >getartbyid.el <<'@EOF'
(defun nnspool-find-article-by-message-id (id)
  "Return full pathname of an article identified by message-ID.
This function uses an external C-program to do the history lookup."
  (save-excursion
    (let ((aname nil) (buffer (get-buffer-create "*newshistory*")))
      (set-buffer buffer)
      (erase-buffer)
      (call-process "getartbyid" nil t nil id)
      (goto-char (point-min))
      (prog1
	  (if (re-search-forward
	       (concat "^" (regexp-quote id)
		       "[ \t].*[ \t]\\([^ \t/]+\\)/\\([0-9]+\\)[ \t]*$") nil t)
	      (let ((group (buffer-substring (match-beginning 1) (match-end 1)))
		    (number (buffer-substring (match-beginning 2) (match-end 2))))
		(concat (nnspool-article-pathname
			 (nnspool-replace-chars-in-string group ?. ?/))
			number)))
	(set-buffer-modified-p nil)
	(kill-buffer buffer)))))



@EOF
set `wc -lwc <getartbyid.el`
if test $1$2$3 != 2379833
then
	echo ERROR: wc results of getartbyid.el are $* should be 23 79 833
fi

chmod 644 getartbyid.el

exit 0
--
Johan Vromans				       jv@mh.nl via internet backbones
Multihouse Automatisering bv		       uucp: ..!{uunet,hp4nl}!mh.nl!jv
Doesburgweg 7, 2803 PL Gouda, The Netherlands  phone/fax: +31 1820 62944/62500
------------------------ "Arms are made for hugging" -------------------------