v15i048: Building custom Yellow Page Maps

Rich Salz rsalz at uunet.uu.net
Thu Jun 9 05:38:09 AEST 1988


Submitted-by: Chuq Von Rospach <chuq at sun.com>
Posting-number: Volume 15, Issue 48
Archive-name: yp-quote

[  It came in two pieces, so I repacked it. --r$ ]
This toy application creates a map called 'quotes'. The program 'quote'
will then access a random data element of this map and print it out.
The source I've used for the data of quotes is the fortune data file,
so this is essentially a Yellow Page based, distributed version of the
fortune program.

See the README for more details. This code is completely
non-proprietary and was written using nothing more than my background
in this stuff, the documentation and man pages. So it's completely
non-proprietary and unrestricted. Feel free to pass it around as widely
as you want -- it was written to teach me how to do this, and I make it
available to help teach you.

Have fun! comments, etc. to me!

chuq, Sun Tech Support
--------------------------------------
#! /bin/sh
# This is a shell archive.  Remove anything before this line, then unpack
# it by saving it into a file and typing "sh file".  To overwrite existing
# files, type "sh file -c".  You can also feed this as standard input via
# unshar, or by typing "sh <file", e.g..  If this archive is complete, you
# will see the following message at the end:
#		"End of archive 1 (of 1)."
# Contents:  Makefile README addpct.c quote.c quote.l quotedb.c
#   strfile.h unstr.c
# Wrapped by rsalz at fig.bbn.com on Wed Jun  8 15:36:35 1988
PATH=/bin:/usr/bin:/usr/ucb ; export PATH
if test -f 'Makefile' -a "${1}" != "-c" ; then 
  echo shar: Will not clobber existing file \"'Makefile'\"
else
echo shar: Extracting \"'Makefile'\" \(356 characters\)
sed "s/^X//" >'Makefile' <<'END_OF_FILE'
X#
X# Makefile for quotedb
X#
XCFLAGS= -g
X
Xall: addpct quote quotedb unstr
X
Xclean: 
X	rm -f addpct quote quotedb unstr core *.o
X
Xaddpct: addpct.o
X	$(CC) $(CFLAGS) addpct.o -o addpct
X
Xquote: quote.o
X	$(CC) $(CFLAGS) quote.o -o quote
X
Xquotedb: quotedb.o
X	$(CC) $(CFLAGS) quotedb.o -o quotedb
X
Xunstr: unstr.o
X	$(CC) $(CFLAGS) unstr.o -o unstr
X
Xunstr.o: strfile.h 
END_OF_FILE
if test 356 -ne `wc -c <'Makefile'`; then
    echo shar: \"'Makefile'\" unpacked with wrong size!
fi
# end of 'Makefile'
fi
if test -f 'README' -a "${1}" != "-c" ; then 
  echo shar: Will not clobber existing file \"'README'\"
else
echo shar: Extracting \"'README'\" \(4755 characters\)
sed "s/^X//" >'README' <<'END_OF_FILE'
XDocumentation for the quote program, a toy application showing how to
Xset up and use a custom Yellow Pages database.
X
XChuq Von Rospach
XSun Tech Support
X
XRelease 1.0: May 2, 1988
X                                   
X                              Manifest:
X
XMakefile
X	Builds everything of interest
XREADME
X	This file
Xaddpct.c
X	Takes a file of quotes separated by blank lines and converts
X	them into the fortune file format separated by a line containing
X	'%%' -- used to convert Moriarty quotes to fortune quotes (and
X	if you don't know what that means, ignore this)
Xquote.c
X	The user program. Looks up random quotes from the quotes Yellow
X	Pages database.
Xquotedb.c
X	This program reads a fortune source file and puts it into a format
X	usable by makedbm to create a Yellow Pages map.
Xstrfile.h
Xunstr.c
X	These public domain programs by Ken Arnold read a compiled fortune
X	file (for instance, /usr/games/lib/fortunes.dat) and turn it into
X	a source file readable by man or the quotedb program.
X
X                         What this stuff is:
X
XThe quote program is a toy application designed to show how to implement
Xyour own custom Yellow Pages maps under SunOS 3.x or 4.0. YP maps are a
Xgood, general purpose distributed database. Because of a dearth of good
Xdocumentation on it, few customer databases have been developed for it. This
Xprogram is aimed at clearing up some of the confusion of how to generate
Xmaps and then access the data in them.
X
XYellow Page maps are created by the "makedbm" program. The format of the
Xthe input data is simple, consisting of a key and data:
X
X	key<whitespace>data<newline>
X
XOnce data is in the map, it can then be pulled out by doing a lookup on the
Xgiven key. At the user level, that is done by:
X
X	ypmatch key mapname
X
Xquote.c shows how to do it from a programmatic view.
X
XHow to Set this up:
X
X	o Compile unstr.c
X	o use unstr.c to de-compile /usr/games/lib/fortunes.dat (note:
X		this requires root, as does all the YP stuff....)
X	o cp the created file to /var/yp/quotes (/usr/etc/yp/quotes
X		under 3.X)
X	o compile quotedb.c, and copy it into /var/yp/quotedb
X	o Add the following rule to /var/yp/Makefile (this will require
X		minor changes, mostly pathnames, to go into 
X		/usr/etc/yp/Makefile. Changes should be obvious
X		in context of the existing YP Makefile)
X
X--------- /var/yp/Makefile ---------------
X# Add quotes to the all rule
Xall: passwd group hosts ethers networks rpc services protocols \
X	netgroup bootparams aliases publickey netid c2secure netmasks \
X	stars ypservers quotes
X
Xquotes.time: $(YPDBDIR)/quotes
X	- at if [ -f $(YPDBDIR)/quotes ]; then \
X		quotedb < $(YPDBDIR)/quotes | $(MAKEDBM) - \
X					$(YPDBDIR)/$(DOM)/quotes; \
X		touch quotes.time; \
X		echo "update quotes"; \
X		if [ ! $(NOPUSH) ]; then \
X			$(YPPUSH) quotes; \
X			echo "pushed quotes"; \
X		else \
X			: ; \
X		fi \
X	else \
X		echo "couldn't find $(YPDBDIR)/quotes"; \
X	fi
X
X# Add to the dependency list
Xquotes: quotes.time
X
X-------- end /var/yp/Makefile -----------
X
X	o cd into /var/yp and run 'make'
X	o if all goes well, the map should exist. "ypwhich -m" should say
X		something like:
X			quotes plaid # replace plaid with your yp server name
X		"ypmatch MAX quotes" should print out a number, and
X		"ypmatch 15 quotes" should print out a quote.
X
X	o compile quote.c. Try running quote. It should print a quote.
X                                   
X                           Final Comments:
X
XNote that quote doesn't support any of the flags that the fortune program
Xhas, such as long, short, obscene, etc. Other than that, this makes a good
Xreplacement for keeping /usr/games on the disk or NFS mounting /usr/games
Xif all you care about is running fortune when you log in. 
X
XPlease note that the program unstr is a public domain program written by Ken
XArnold to unpack the public domain fortune's data files. This format happens
Xto also work with the SunOS fortune files (not surprising, since Ken wrote
Xthe original fortune, which we've adopted).
X
XAlso, all of this code was written from the man pages and documentation, not
Xfrom any proprietary source. It is, therefore, not proprietary to either Sun
Xor AT&T source code agreements, so you can pass it around as widely as you
Xwant. That's the point, of course -- this is designed to be educational.
X
XNote that because of inherent (but very large) limitations of the ndbm()
Xpackage, it is possible to build a data set too large for YP to handle.
XIf you get that, you'll see errors from makedbm and the map won't create
Xor update. All you can do is make the dataset smaller. The only place I've
Xseen this is with my special, 6000 entry quote file, but you've been warned.
XAnd no, I don't distribute my quote file -- it's too large.
X
Xcomments, thoughts, feedback, criticism and money are all welcome. 
END_OF_FILE
if test 4755 -ne `wc -c <'README'`; then
    echo shar: \"'README'\" unpacked with wrong size!
fi
# end of 'README'
fi
if test -f 'addpct.c' -a "${1}" != "-c" ; then 
  echo shar: Will not clobber existing file \"'addpct.c'\"
else
echo shar: Extracting \"'addpct.c'\" \(356 characters\)
sed "s/^X//" >'addpct.c' <<'END_OF_FILE'
X/*
X * This takes a file with quotes delimited by a blank line (typically
X * a moriarty quote file) and turns it into a %% delimited file that
X * can be imported into a fortune database
X *
X * chuq von rospach
X */
X
X#include <stdio.h>
X
Xmain()
X{
X    char line[BUFSIZ];
X
X    while (gets(line))
X	if (strlen(line))
X	    puts(line);
X	else
X	    printf("%%%%\n");
X}
END_OF_FILE
if test 356 -ne `wc -c <'addpct.c'`; then
    echo shar: \"'addpct.c'\" unpacked with wrong size!
fi
# end of 'addpct.c'
fi
if test -f 'quote.c' -a "${1}" != "-c" ; then 
  echo shar: Will not clobber existing file \"'quote.c'\"
else
echo shar: Extracting \"'quote.c'\" \(1520 characters\)
sed "s/^X//" >'quote.c' <<'END_OF_FILE'
X#include <stdio.h>
X#include <rpcsvc/ypclnt.h>
X
X#define MAXLEN 4096
X#define randint(maxval) ((random() % (maxval)) + 1)
X
Xchar dom_name[BUFSIZ];
X
Xmain()
X{
X    char *quotebuf;
X    int quotelen;
X    char *maxbuf;
X    int maxlen;
X    int maxnum = 0;
X    int quotenum = 0;
X    char *c;
X    char *index();
X
X    srandom(getpid()); /* initialize random numbers */
X
X    /* who are we? */
X    if (getdomainname(dom_name, BUFSIZ)) {
X	fprintf(stderr, "No domainname set\n");
X	exit(1);
X    }
X
X    /* Get the highest quote in the system */
X    get_match("MAX", &maxbuf, &maxlen);
X    maxnum = atoi(maxbuf);
X
X    /* Generate a random number between 1 and maxnum */
X    quotenum = randint(maxnum);
X    if (quotenum < 0 || quotenum > maxnum) {
X	fprintf(stderr, "Illegal randint value!\n");
X	exit(1);
X    }
X
X    /* now grab that quote */
X    sprintf(maxbuf,"%d",quotenum);
X    get_match(maxbuf, &quotebuf, &quotelen);
X
X    /* turn all ^A characters to newlines.
X     * turn all ^B characters to tabs.
X     * needed to allow proper insertion into a yp database, since makedbm
X     * uses both as delimiters.
X     */
X    while ((c = index(quotebuf,'\001')))
X	*c = '\n';
X
X    while ((c = index(quotebuf,'\002')))
X	*c = '\t';
X    
X    /* print it out */
X    printf("%s",quotebuf);
X}
X
X/* get the largest quote from key MAX */
X
Xget_match(key, retval, retlen)
X    char *key;
X    char **retval;
X    int *retlen;
X{
X
X    if (yp_match(dom_name, "quotes", key, strlen(key), retval, retlen)) {
X	fprintf(stderr, "error in ypmatch\n");
X	exit(1);
X    }
X}
END_OF_FILE
if test 1520 -ne `wc -c <'quote.c'`; then
    echo shar: \"'quote.c'\" unpacked with wrong size!
fi
# end of 'quote.c'
fi
if test -f 'quote.l' -a "${1}" != "-c" ; then 
  echo shar: Will not clobber existing file \"'quote.l'\"
else
echo shar: Extracting \"'quote.l'\" \(1457 characters\)
sed "s/^X//" >'quote.l' <<'END_OF_FILE'
X.TH QUOTE 6
X.SH NAME
Xquote - read quotes from a Yellow Pages Database
X.SH SYNOPSIS
X.B quote
X.br
X.B quotedb
X.SH DESCRIPTION
X.I Quote
Xis a toy application designed to show how to create and access a custom
XYellow Pages database.
XIt creates a Yellow Pages version of the program
Xfortune.
X.PP
X.I Quote
Xis the user program.
XIt reads the Yellow Pages database "quotes" to get a random quote
Xout of it.
X.PP
X.I Quotedb
Xis the program that takes a "fortune" style source file and turns it into
Xa format that can be fed to 
X.I makedbm
Xto create the Yellow Pages database.
X.PP
XSee the README and the source for the grotty details of how to modify the
XYP Makefile and how all this stuff fits together.
X.SH AUTHOR
XChuq Von Rospach, Sun Microsystems Tech Support (chuq at sun.COM)
X.SH DIAGNOSTICS
XGenerally self-documenting, as they say. At least in theory.
X.PP
XError messages from 
X.I makedbm
Xmay not be as clear as you might hope.
X.SH BUGS
XThere are limits to the amount of data that can be shoved in a ndbm(3)
Xdatabase.
XLarge text based items (like quotes) will fill up a database faster than
Xsmall ones.
XSince YP uses ndbm(3) for internal storage, this means you might
Xget creation errors on very large fortune files.
XIf you get them, all you can do is shrink the data-set. In all practical
Xcases,
Xthis is probably not a problem.
XI had to build an extremely large quotes file to find this out (the hard
Xway, of course).
XThanks to moriarty for making this bug findable.
X
END_OF_FILE
if test 1457 -ne `wc -c <'quote.l'`; then
    echo shar: \"'quote.l'\" unpacked with wrong size!
fi
# end of 'quote.l'
fi
if test -f 'quotedb.c' -a "${1}" != "-c" ; then 
  echo shar: Will not clobber existing file \"'quotedb.c'\"
else
echo shar: Extracting \"'quotedb.c'\" \(878 characters\)
sed "s/^X//" >'quotedb.c' <<'END_OF_FILE'
X#include <stdio.h>
X
X#define MAXLEN 450
X
Xchar quotebuf[MAXLEN];
Xchar line[MAXLEN];
Xint numq = 0;
X
Xchar *strcat();
Xchar *strcpy();
X
Xmain()
X{
X
X    char *c, *index();
X    int endit = 0;
X
X    while (gets(line)) {
X	if (line[0] == '%' && (line[1] == '%' || line[1] == '-')) {
X
X	    if (strlen(quotebuf)) {
X		numq++;
X
X	    /*
X	     * mark all newlines and tabs with special character flags so
X	     * you don't confuse makedbm
X	     */
X
X		while ((c = index(quotebuf, '\n')))
X		    *c = '\001';
X
X		while ((c = index(quotebuf, '\t')))
X		    *c = '\002';
X
X		printf("%d\t%s\n", numq, quotebuf);
X		strcpy(quotebuf, "");
X	    }
X	} else {
X
X	    if ((strlen(line) + strlen(quotebuf)) > MAXLEN) {
X/*		fprintf(stderr, "\nLong quote:\n%s\n", quotebuf); */
X		strcpy(quotebuf, "");
X	    } else {
X		strcat(quotebuf, line);
X		strcat(quotebuf, "\001");
X	    }
X	}
X    }
X    printf("MAX\t%d\n", numq);
X}
END_OF_FILE
if test 878 -ne `wc -c <'quotedb.c'`; then
    echo shar: \"'quotedb.c'\" unpacked with wrong size!
fi
# end of 'quotedb.c'
fi
if test -f 'strfile.h' -a "${1}" != "-c" ; then 
  echo shar: Will not clobber existing file \"'strfile.h'\"
else
echo shar: Extracting \"'strfile.h'\" \(627 characters\)
sed "s/^X//" >'strfile.h' <<'END_OF_FILE'
X/* @(#)strfile.h	1.2 (Berkeley) 5/14/81 */
X# ifndef	__STRFILE__
X
X# define	__STRFILE__
X
X# include	<sys/types.h>
X
X# define	MAXDELIMS	3
X
X/*
X * bits for flag field
X */
X
X# define	STR_RANDOM	0x1
X# define	STR_ORDERED	0x2
X
Xtypedef struct {		/* information table */
X	unsigned long	str_numstr;		/* # of strings in the file */
X	unsigned long	str_longlen;		/* length of longest string */
X	unsigned long	str_shortlen;		/* length of shortest string */
X	long		str_delims[MAXDELIMS];	/* delimiter markings */
X	off_t		str_dpos[MAXDELIMS];	/* delimiter positions */
X	short		str_flags;		/* bit field for flags */
X} STRFILE;
X
X# endif		__STRFILE__
END_OF_FILE
if test 627 -ne `wc -c <'strfile.h'`; then
    echo shar: \"'strfile.h'\" unpacked with wrong size!
fi
# end of 'strfile.h'
fi
if test -f 'unstr.c' -a "${1}" != "-c" ; then 
  echo shar: Will not clobber existing file \"'unstr.c'\"
else
echo shar: Extracting \"'unstr.c'\" \(3701 characters\)
sed "s/^X//" >'unstr.c' <<'END_OF_FILE'
X# include	<stdio.h>
X# include	<ctype.h>
X# include	"strfile.h"
X
X# define	TRUE	1
X# define	FALSE	0
X
X/*
X *	This program un-does what "strfile" makes, thereby obtaining the
X * original file again.  This can be invoked with the name of the output
X * file, the input file, or both. If invoked with only a single argument
X * ending in ".dat", it is pressumed to be the input file and the output
X * file will be the same stripped of the ".dat".  If the single argument
X * doesn't end in ".dat", then it is presumed to be the output file, and
X * the input file is that name prepended by a ".dat".  If both are given
X * they are treated literally as the input and output files.
X *
X *	Ken Arnold		Aug 13, 1978
X */
X
X# define	DELIM_CH	'-'
X
Xchar	Infile[100],			/* name of input file */
X	Outfile[100],			/* name of output file */
X	Delimch = '%';			/* delimiter character */
X
Xshort	Oflag = FALSE;			/* use order of initial table */
X
XFILE	*Inf, *Outf;
X
Xchar	*rindex(), *malloc(), *strcat(), *strcpy();
X
Xmain(ac, av)
Xint	ac;
Xchar	**av;
X{
X	register int	c;
X	register int	nstr, delim;
X	static STRFILE	tbl;		/* description table */
X
X	getargs(ac, av);
X	if ((Inf = fopen(Infile, "r")) == NULL) {
X		perror(Infile);
X		exit(-1);
X		/* NOTREACHED */
X	}
X	if ((Outf = fopen(Outfile, "w")) == NULL) {
X		perror(Outfile);
X		exit(-1);
X		/* NOTREACHED */
X	}
X	(void) fread((char *) &tbl, sizeof tbl, 1, Inf);
X	if (Oflag) {
X		order_unstr(&tbl);
X		exit(0);
X		/* NOTREACHED */
X	}
X	nstr = tbl.str_numstr;
X	(void) fseek(Inf, (off_t) (sizeof (off_t) * (nstr + 1)), 1);
X	delim = 0;
X	nstr = 0;
X	while ((c = getc(Inf)) != EOF)
X		if (c != '\0')
X			putc(c, Outf);
X		else if (nstr != tbl.str_numstr - 1)
X			if (++nstr == tbl.str_delims[delim]) {
X				fprintf(Outf, "%c-\n", Delimch);
X				delim++;
X			}
X			else
X				fprintf(Outf, "%c%c\n", Delimch, Delimch);
X	exit(0);
X	/* NOTREACHED */
X}
X
Xgetargs(ac, av)
Xregister int	ac;
Xregister char	*av[];
X{
X	register int	i;
X	register char	*sp;
X	register int	j;
X	register short	bad;
X
X	bad = 0;
X	for (i = 1; i < ac; i++)  {
X		if (av[i][0] != '-') {
X			(void) strcpy(Infile, av[i]);
X			if (i + 1 >= ac) {
X				(void) strcpy(Outfile, Infile);
X				if ((sp = rindex(av[i], '.')) &&
X				    strcmp(sp, ".dat") == 0)
X					Outfile[strlen(Outfile) - 4] = '\0';
X				else
X					(void) strcat(Infile, ".dat");
X			}
X			else
X				(void) strcpy(Outfile, av[i + 1]);
X			break;
X		}
X		else if (av[i][1] == '\0') {
X			printf("usage: unstr [-o] [-cC] datafile[.dat] [outfile]\n");
X			exit(0);
X			/* NOTREACHED */
X		}
X		else
X			for (sp = &av[i][1]; *sp != '\0'; sp++)
X				switch (*sp) {
X				  case 'o':	/* print out in seekptr order */
X					Oflag++;
X					break;
X				  case 'c': /* new delimiting char */
X					if ((Delimch = *++sp) == '\0') {
X						--sp;
X						Delimch = *av[++i];
X					}
X					if (!isascii(Delimch)) {
X						fprintf(stderr,
X							"bad delimiting character: 0x%x\n",
X							Delimch);
X						bad++;
X					}
X					break;
X				  default:
X					fprintf(stderr, "unknown flag: '%c'\n",
X						*sp);
X					bad++;
X					break;
X				}
X	}
X	if (bad) {
X		printf("use \"%s -\" to get usage\n", av[0]);
X		exit(-1);
X	}
X}
X
Xorder_unstr(tbl)
XSTRFILE	*tbl;
X{
X	register int	i, c;
X	register int	delim;
X	register off_t	*seekpts;
X
X	seekpts = (off_t *) malloc(sizeof *seekpts * tbl->str_numstr);	/* NOSTRICT */
X	if (seekpts == NULL) {
X		perror("malloc");
X		exit(-1);
X		/* NOTREACHED */
X	}
X	(void) fread((char *) seekpts, sizeof *seekpts, (int) tbl->str_numstr,
X		     Inf);
X	delim = 0;
X	for (i = 0; i < tbl->str_numstr; i++, seekpts++) {
X		if (i != 0)
X			if (i == tbl->str_delims[delim]) {
X				fputs("%-\n", Outf);
X				delim++;
X			}
X			else
X				fputs("%%\n", Outf);
X		(void) fseek(Inf, *seekpts, 0);
X		while ((c = getc(Inf)) != '\0')
X			putc(c, Outf);
X	}
X}
END_OF_FILE
if test 3701 -ne `wc -c <'unstr.c'`; then
    echo shar: \"'unstr.c'\" unpacked with wrong size!
fi
# end of 'unstr.c'
fi
echo shar: End of archive 1 \(of 1\).
cp /dev/null ark1isdone
MISSING=""
for I in 1 ; do
    if test ! -f ark${I}isdone ; then
	MISSING="${MISSING} ${I}"
    fi
done
if test "${MISSING}" = "" ; then
    echo You have the archive.
    rm -f ark[1-9]isdone
else
    echo You still need to unpack the following archives:
    echo "        " ${MISSING}
fi
##  End of shell archive.
exit 0
-- 
Please send comp.sources.unix-related mail to rsalz at uunet.uu.net.



More information about the Comp.sources.unix mailing list