[alt.sources] dls/describe part 2 of 2

timcc@csv.viccol.edu.au (Tim Cook) (03/23/91)

#!/bin/sh
# this is dls.02 (part 2 of a multipart archive)
# do not concatenate these parts, unpack them in order with /bin/sh
# file describe.c continued
#
if test ! -r _shar_seq_.tmp; then
	echo 'Please unpack part 1 first!'
	exit 1
fi
(read Scheck
 if test "$Scheck" != 2; then
	echo Please unpack part "$Scheck" next!
	exit 1
 else
	exit 0
 fi
) < _shar_seq_.tmp || exit 1
if test ! -f _shar_wnt_.tmp; then
	echo 'x - still skipping describe.c'
else
echo 'x - continuing file describe.c'
sed 's/^X//' << 'SHAR_EOF' >> 'describe.c' &&
X	 perror2 (program_name, file) ;
X	 exit (2) ; } }
X   if (chdir (directory) == -1) {
X      perror2 (program_name, directory) ;
X      exit (2) ; }
X   while (! feof (descriptions)) {
X      if (fgets (buffer, sizeof (buffer), descriptions) != NULL_CP) {
X	 n = sscanf (buffer, "\"%[^\"]\" %[^\n]\n", file_name, description) ;
X	 if (n < 2)
X	    n = sscanf (buffer, "%s %[^\n]\n", file_name, description) ;
X	 if (n == 2 && file_name[0] != '#') {
X	    if (stat (file_name, &status) == -1) {
X	       perror2 (program_name, file_name) ; }
X	    else {
X	       set_description (file_name, status.st_ino, description) ; } } }
X      }
X   fclose (descriptions) ;
X   }
X
X
#define uninitialised	0
#define not_found	1
#define initialised	2
X
static int desc_state = uninitialised ;
X
static
int init_desc_file (file_name, read_only)
X   char *file_name ;
X   int read_only ;
{
X   static char desc_file[MAXNAMLEN+1] ;
X   char new_desc_file[MAXNAMLEN+1] ;
X   char name[MAXNAMLEN+1] ;
X   char *p ;
#ifdef NDBM
X   int open_flags ;
#else
X   struct stat status ;
X   int fd ;
#endif
X
X   strcpy (new_desc_file, file_name) ;
X   if (desc_state == uninitialised || strcmp (desc_file, new_desc_file) != 0) {
X
X      /* Changing desc_file */
X
X      strcpy (desc_file, new_desc_file) ;
X      if (*new_desc_file != EOS)
X	 strcat (new_desc_file, "/") ;
X      strcat (new_desc_file, ".desc.pag") ;
X      p = strrchr (new_desc_file, '.') ;
X
#ifdef NDBM
X
X      /* By crikey, it's easier this way! */
X
X      *p = EOS ;
X
X      if (read_only)
X	 open_flags = O_RDONLY ;
X      else
X	 open_flags = O_RDWR | O_CREAT ;
X      if ((desc_database = dbm_open (new_desc_file, open_flags, 0666))
X               == (DBM *) NULL) {
X	 desc_state = not_found ;
X	 return FALSE && (! read_only) ; }
X      desc_state = initialised ;
X
#else	/* DBM */
X
X      if (stat (new_desc_file, &status) != -1) {	/* File exists */
X	 *p = EOS ;
X	 if (dbminit (new_desc_file) < 0) {
X	    desc_state = not_found ;
X	    return FALSE ; }
X	 else
X	    desc_state = initialised ; }
X      else {
X	 if (read_only) {
X	    desc_state = not_found ;
X	    return FALSE ; }		/* Signal that there isn't one */
X	 else {
X	    /* Create .desc.(pag|dir) files */
X	    if ((fd = open (new_desc_file, O_CREAT | O_EXCL | O_RDWR, 0666))
X		< 0) {
X	       perror2 (program_name, new_desc_file) ;
X	       exit (2) ; }
X	    close (fd) ;
X	    strcpy (p, ".dir") ;
X	    if ((fd = open (new_desc_file, O_CREAT | O_EXCL | O_RDWR, 0666))
X		< 0) {
X	       perror2 (program_name, new_desc_file) ;
X	       exit (2) ; }
X	    close (fd) ;
X	    *p = EOS ;
X
X	    /* Start up DBM */
X	    if (dbminit (new_desc_file) < 0)
X	       desc_state = not_found ;
X	    else
X	       desc_state = initialised ; } }
#endif	/* NDBM */
X      }
X   return TRUE ;
X   }
X
X
static
void set_description (file_name, inode, description)
X   char *file_name ;
X   ino_t inode ;
X   char *description ;
{
X   datum key, content ;
X
X   /* Store the description, indexed by the file name */
X   key.dptr = file_name ;
X   key.dsize = strlen (file_name) ;
X   if (key.dsize == sizeof (ino_t))
X      key.dsize++ ;
X   content.dptr = description ;
X   content.dsize = strlen (description) + 1 ;
#ifdef NDBM
X   if (dbm_store (desc_database, key, content, DBM_REPLACE) < 0)
#else
X   if (store (key, content) < 0)
#endif
X   {
X      perror2 (program_name, file_name) ;
X      exit (2) ; }
X
X   /* Store the file name, indexed by the inode number */
X   key.dptr = (char *) &inode ;
X   key.dsize = sizeof (ino_t) ;
X   content.dptr = file_name ;
X   content.dsize = strlen (file_name) ;
#ifdef NDBM
X   if (dbm_store (desc_database, key, content, DBM_REPLACE) < 0)
#else
X   if (store (key, content) < 0)
#endif
X   {
X      perror2 (program_name, file_name) ;
X      exit (2) ; }
X   }
X
X
static
void delete_description (file_name, inode)
X   char *file_name ;
X   ino_t inode ;
{
X   datum key ;
X
X   key.dptr = (char *) &inode ;
X   key.dsize = sizeof (ino_t) ;
#ifdef NDBM
X   dbm_delete (desc_database, key) ;
#else
X   delete (key) ;
#endif
X   key.dptr = file_name ;
X   key.dsize = strlen (file_name) ;
X   if (key.dsize == sizeof (ino_t))
X      key.dsize++ ;
#ifdef NDBM
X   dbm_delete (desc_database, key) ;
#else
X   delete (key) ;
#endif
X   }
X
X
static
void list_descriptions ()
{
X   datum key, last_key, content ;
X   char file_name[MAXNAMLEN+1] ;
X   int file_name_length ;
X   int gap ;
X
#ifdef NDBM
X   for (key = dbm_firstkey (desc_database) ; key.dptr != NULL_CP ;
X	 key = dbm_nextkey (desc_database))
#else
X   for (key = firstkey () ; key.dptr != NULL_CP ; key = nextkey (last_key))
#endif
X   {
X      last_key = key ;
X      if (key.dsize != sizeof (ino_t)) {
#ifdef NDBM
X	 content = dbm_fetch (desc_database, key) ;
#else
X	 content = fetch (key) ;
#endif
X	 file_name_length = key.dsize ;
X	 if (file_name_length == sizeof (ino_t) + 1
X	     && key.dptr[sizeof(ino_t)] == EOS)
X	    file_name_length-- ;
X	 strncpy (file_name, key.dptr, file_name_length) ;
X	 file_name[file_name_length] = EOS ;
X	 if (strpbrk (file_name, " \t") != NULL_CP) {
X	    printc ('"') ;
X	    print (file_name) ;
X	    printc ('"') ;
X	    gap = 18 - file_name_length ; }
X	 else {
X	    print (file_name) ;
X	    gap = 20 - file_name_length ; }
X	 printc (' ') ;		/* We need at least one space */
X	 while (gap-- > 0)
X	    printc (' ') ;
X	 print (content.dptr) ;
X         printc ('\n') ; } }
X   }
SHAR_EOF
echo 'File describe.c is complete' &&
chmod 0640 describe.c ||
echo 'restore of describe.c failed'
Wc_c="`wc -c < 'describe.c'`"
test 8873 -eq "$Wc_c" ||
	echo 'describe.c: original size 8873, current size' "$Wc_c"
rm -f _shar_wnt_.tmp
fi
# ============= list.c ==============
if test -f 'list.c' -a X"$1" != X"-c"; then
	echo 'x - skipping list.c (File already exists)'
	rm -f _shar_wnt_.tmp
else
> _shar_wnt_.tmp
echo 'x - extracting list.c (Text)'
sed 's/^X//' << 'SHAR_EOF' > 'list.c' &&
/* list.c -	List manipulation routines
X *
X * SYNOPSIS
X *	void list_init (struct list *list) ;
X *
X *		Initializes the list.  This is actually only a macro,
X *		and it does not free any storage that may have been
X *		allocated to the list.
X *
X *	void list_free (struct list *list) ;
X *
X *		Deallocates and initializes the list.
X *
X *	void list_push (struct list *list, void *element) ;
X *
X *		Adds the element to the end of the list.
X *
X *	void *list_pop (struct list *list) ;
X *
X *		Returns the last element in the list and removes it.
X *		The list is automatically deallocated using list_free
X *		when the last element has been popped.
X *
X *	void *list_shift (struct list *list) ;
X *
X *		Returns the first element in the list and removes it
X *		The list is automatically deallocated using list_free
X *		when the last element has been shifted.
X *
X *	void list_sort (struct list *list, int (*compare) ()) ;
X *
X *		Sorts the list using compare() (like qsort(3))
X *
X * Copyright (c) 1991 Tim Cook.
X * Non-profit distribution allowed.  See README for details.
X */
X
static char rcsid[] = "$Header: list.c 1.0 91/03/22 $" ;
X
#define _LIST_C
X
#include <list.h>
X
#define NULL	0
X
extern void *malloc () ;
extern void *realloc () ;
extern int free () ;
X
#define INITIAL_ENTRIES	512
X
X
void list_free (list)
X   struct list *list ;
{
X   free (list->s_start) ;
X   list->s_start = (void **) NULL ;
X   }
X
X
void list_push (list, element)
X   struct list *list ;
X   void *element ;
{
X   register unsigned int x, y, z ;
X
X   if (list->start == (void **) NULL) {
X      x = sizeof (void *) * INITIAL_ENTRIES ;
X      list->s_start = (void **) malloc (x) ;
X      list->s_end = list->s_start + INITIAL_ENTRIES ;
X      list->start = list->s_start ;
X      list->end = list->start ;
X      *list->end = element ; }
X   else {
X      if (list->end >= list->s_end) {
X	 x = (unsigned int) list->s_end - (unsigned int) list->s_start ;
X	 y = (unsigned int) list->start - (unsigned int) list->s_start ;
X	 z = (unsigned int) list->end - (unsigned int) list->s_start ;
X	 x = x << 1 ;
X	 list->s_start = (void **) realloc (list->s_start, x) ;
X	 list->s_end = (void **) ((unsigned int) list->s_start + x) ;
X	 list->start = (void **) ((unsigned int) list->s_start + y) ;
X	 list->end = (void **) ((unsigned int) list->s_start + z) ; }
X      list->end++ ;
X      *list->end = element ; } }
X
X
void *list_shift (list)
X   struct list *list ;
{
X   if (list->start > list->end) {
X      list_free (list) ;
X      return (void *) NULL ; }
X   else
X      return *list->start++ ;
X   }
X
X
void *list_pop (list)
X   struct list *list ;
{
X   if (list->start == (void **) NULL)
X      return (void *) NULL ;
X   else {
X      if (list->end == list->start) {
X	 list_free (list) ;
X	 return *list->end ; }
X      else
X	return *list->end-- ; }
X   }
X
X
void list_sort (list, compare)
X   struct list *list ;
X   int (*compare) () ;
{
X   register unsigned int x ;
X
X   x = (unsigned int) list->end - (unsigned int) list->start ;
X   x = x / sizeof (void *)  + 1 ;
X   qsort (list->start, x, sizeof (void *), compare) ;
X   }
SHAR_EOF
chmod 0640 list.c ||
echo 'restore of list.c failed'
Wc_c="`wc -c < 'list.c'`"
test 3043 -eq "$Wc_c" ||
	echo 'list.c: original size 3043, current size' "$Wc_c"
rm -f _shar_wnt_.tmp
fi
# ============= list.h ==============
if test -f 'list.h' -a X"$1" != X"-c"; then
	echo 'x - skipping list.h (File already exists)'
	rm -f _shar_wnt_.tmp
else
> _shar_wnt_.tmp
echo 'x - extracting list.h (Text)'
sed 's/^X//' << 'SHAR_EOF' > 'list.h' &&
/* list.h -	Definitions for list manipulation
X *
X * Copyright (c) 1991 Tim Cook.
X * Non-profit distribution allowed.  See README for details.
X *
X * $Header: list.h 1.0 91/03/22 $
X */
X
#ifndef _LIST_H
#define _LIST_H
X
struct list {
X   void **start ;	/* First element (NULL if empty) */
X   void **end ;		/* Last element */
X   void **s_start ;	/* Beginning of storage */
X   void **s_end ;	/* Just past end of storage */
X   } ;
X
#ifndef _LIST_C
#define list_init(l)	((l)->start = (void **) 0)
extern void list_push () ;
extern void *list_pop () ;
extern void *list_shift () ;
extern void list_sort () ;
extern void list_free () ;
#endif	/* _LIST_C */
X
#endif	/* _LIST_H */
SHAR_EOF
chmod 0640 list.h ||
echo 'restore of list.h failed'
Wc_c="`wc -c < 'list.h'`"
test 669 -eq "$Wc_c" ||
	echo 'list.h: original size 669, current size' "$Wc_c"
rm -f _shar_wnt_.tmp
fi
# ============= smalloc.c ==============
if test -f 'smalloc.c' -a X"$1" != X"-c"; then
	echo 'x - skipping smalloc.c (File already exists)'
	rm -f _shar_wnt_.tmp
else
> _shar_wnt_.tmp
echo 'x - extracting smalloc.c (Text)'
sed 's/^X//' << 'SHAR_EOF' > 'smalloc.c' &&
/* smalloc.c -	Allocate a small chunk of memory that will not be freed
X *
X * SYNOPSIS
X *	void *smalloc (size_t length)
X *
X * DESCRIPTION
X *	smalloc allocates large chunks of memory from malloc(3), and
X *	parcels it out in much smaller chunks.  It does not waste
X *	time recording where these chunks are, as it knows the memory
X *	will only be released when the calling process terminates.
X *
X * Copyright (c) 1991 Tim Cook.
X * Non-profit distribution allowed.  See README for details.
X */
X
static char rcsid[] = "$Header: smalloc.c 1.0 91/03/22 $" ;
X
#include <sys/types.h>
X
#define NULL	((void *) 0)
X
extern void *malloc () ;
X
#define MALLOC_CHUNK_SIZE	16384
X
#ifdef DEBUG
int _smalloc_chunks = 0 ;
int _smalloc_areas = 0 ;
#endif
X
X
void *smalloc (length)
X   size_t length ;
{
X   static void *virgin = NULL ;		/* Points to next available byte */
X   static void *end = NULL ;		/* Points just past end of storage */
X   void *p ;
X
X   if (length > (size_t) MALLOC_CHUNK_SIZE)
X      return NULL ;
X   if (virgin == NULL || ((u_long) virgin + (u_long) length) > (u_long) end) {
X      virgin = malloc (MALLOC_CHUNK_SIZE) ;
X      if (virgin == NULL)
X	 return NULL ;
#ifdef DEBUG
X      _smalloc_areas++ ;
#endif
X      end = (void *) ((u_long) virgin + (u_long) MALLOC_CHUNK_SIZE) ; }
X   p = virgin ;
X   virgin = (void *) ((u_long) virgin + (u_long) length) ;
#ifdef DEBUG
X   _smalloc_chunks++ ;
#endif
X   return p ;
X   }
SHAR_EOF
chmod 0640 smalloc.c ||
echo 'restore of smalloc.c failed'
Wc_c="`wc -c < 'smalloc.c'`"
test 1412 -eq "$Wc_c" ||
	echo 'smalloc.c: original size 1412, current size' "$Wc_c"
rm -f _shar_wnt_.tmp
fi
# ============= vclib.h ==============
if test -f 'vclib.h' -a X"$1" != X"-c"; then
	echo 'x - skipping vclib.h (File already exists)'
	rm -f _shar_wnt_.tmp
else
> _shar_wnt_.tmp
echo 'x - extracting vclib.h (Text)'
sed 's/^X//' << 'SHAR_EOF' > 'vclib.h' &&
/*	vclib.h - VClib definitions file (trimmed for release with dls)
X *
X * Copyright (c) 1991 Tim Cook.
X * Non-profit distribution allowed.  See README for details.
X *
X * $Header: vclib.h 1.0 91/03/22 $
X */
X
#ifndef   VClib
#define   VClib		1
X
/***	M a c r o   C o n s t a n t   D e f i n i t i o n s    ***/
X
/* To enable the use of Boolean variables and constants */
X
typedef   unsigned int	bool ;
X
#ifndef	TRUE
X
#define   TRUE		1
#define   FALSE		0
X
#endif	/* defined (TRUE) */
X
/***	M a c r o   T y p e   D e f i n i t i o n s    ***/
X
/***	t y p e d e f   T y p e   D e f i n i t i o n s    ***/
X
/***	S t r u c t u r e   a n d   U n i o n   D e f i n i t i o n s    ***/
X
#ifdef	sequent	/* If a sequent, shorts are 16 bits */
X
typedef char		byte ;
typedef unsigned char	ubyte ;
typedef	short		word ;
typedef	unsigned short	uword ;
typedef int		longword ;
typedef unsigned int	ulongword ;
X
#endif	/* sequent */
X
/***	M a c r o   F u n c t i o n   D e f i n i t i o n s    ***/
X
/*   To provide a consistent interface to stdio routines */
X
#define	print(s)	fputs(s,stdout)
#define	fprint(f,s)	fputs(s,f)
#define printc(c)	fputc(c,stdout)
#define fprintc(f,c)	fputc(c,f)
X
/***	M i s c e l l a n e o u s   M a c r o   D e f i n i t i o n s    ***/
X
/***	V C l i b   R o u t i n e   D e f i n i t i o n s    ***/
X
#endif	/* ! defined (VClib) */
SHAR_EOF
chmod 0640 vclib.h ||
echo 'restore of vclib.h failed'
Wc_c="`wc -c < 'vclib.h'`"
test 1344 -eq "$Wc_c" ||
	echo 'vclib.h: original size 1344, current size' "$Wc_c"
rm -f _shar_wnt_.tmp
fi
# ============= split_pathname.c ==============
if test -f 'split_pathname.c' -a X"$1" != X"-c"; then
	echo 'x - skipping split_pathname.c (File already exists)'
	rm -f _shar_wnt_.tmp
else
> _shar_wnt_.tmp
echo 'x - extracting split_pathname.c (Text)'
sed 's/^X//' << 'SHAR_EOF' > 'split_pathname.c' &&
/* split_pathname.c -	Split path into directory and name
X *
X * SYNOPSIS
X *	char *split_pathname (const char *pathname, char *directory,
X *              char *name)
X *
X * DESCRIPTION
X *	Extracts the directory part and the name part of a Unix pathname.
X *	Returns a pointer to the name part.
X *
X * Copyright (c) 1991 Tim Cook.
X * Non-profit distribution allowed.  See README for details.
X */
X
static char rcsid[] = "$Header: split_pathname.c 1.0 91/03/22 $" ;
X
#include <string.h>
#define NULL_CP		((char *) 0)
#define EOS		'\0'
X
X
char *split_pathname (pathname, directory, name)
X   char *pathname, *directory, *name ;
{
X   char *p ;
X
X   strcpy (directory, pathname) ;
X   while ((p = strrchr (directory, '/')) != NULL_CP && p[1] == EOS) *p = EOS ;
X   if (p == NULL_CP) {
X      strcpy (name, pathname) ;
X      directory[0] = EOS ; }
X   else {
X      strcpy (name, p + 1) ;
X      if (p == directory) {	/* The slash is at the start of pathname */
X	 directory[1] = EOS ; }
X      else {
X	 *p = EOS ; } }
X   return name ; }
X
X
#ifdef TEST
#include <stdio.h>
X
int main (argc, argv)
X   int argc ;
X   char **argv ;
{
X   char directory[256] ;
X   char name[256] ;
X
X   if (split_pathname (argv[1], directory, name) == NULL_CP) {
X      fprintf (stderr, "%s: couldn't parse \"%s\"\n", argv[0], argv[1]) ; }
X   else {
X      printf ("pathname:  \"%s\"\ndirectory: \"%s\"\nname:     \"%s\"\n",
X	 argv[1], directory, name) ; }
X   }
#endif
SHAR_EOF
chmod 0640 split_pathname.c ||
echo 'restore of split_pathname.c failed'
Wc_c="`wc -c < 'split_pathname.c'`"
test 1417 -eq "$Wc_c" ||
	echo 'split_pathname.c: original size 1417, current size' "$Wc_c"
rm -f _shar_wnt_.tmp
fi
# ============= dls.man ==============
if test -f 'dls.man' -a X"$1" != X"-c"; then
	echo 'x - skipping dls.man (File already exists)'
	rm -f _shar_wnt_.tmp
else
> _shar_wnt_.tmp
echo 'x - extracting dls.man (Text)'
sed 's/^X//' << 'SHAR_EOF' > 'dls.man' &&
.\" dls.man -	Man page for descriptive ls
.\"
.\" Copyright (c) 1991 Tim Cook.
.\" Non-profit distribution allowed.  See README for details.
.\"
.\" $Header: dls.man 1.0 91/03/22 $
.\"
.TH DLS 1 "20 March, 1991"
.UC 4
.SH NAME
dls \- Descriptive ls
.SH SYNOPSIS
.B dls
[
flags
] [
file ...
]
.SH DESCRIPTION
.I Dls
lists files and directories in the manner of ls(1), but includes a
descriptive comment for each file that has a description set.
By default,
.I dls
lists the file name, size of the file in bytes and the description.
If the file is a directory, a hyphen (-) is shown instead of the size,
and if the file is a directory that contains other directories, an equals
sign (=) is shown.
.PP
Descriptions are set by
.I describe
and are stored in a hidden file in the same directory as the files for
which descriptions are held.
.\" The descriptions are matched to files by name
.\" and inode-number, so renaming or editing the file in the same directory
.\" will not cause the loss of its description.
.PP
Options:
.TP 1i
.B \-d
List the date and time of each file.  The last modification date and time
are listed after the file size, in the same format used by ls(1).
.TP 1i
.B \-e
List everything, even inaccessible files.
By default, files that cannot be read or executed are ignored.
.TP 1i
.B \-t
Sort by last modification time.  Most recently modified files come first.
.TP 1i
.BI \-f width
Use a maximum of
.I width
columns to display the file name.
If a file name is longer than
.I width,
it may expand into the area used to show the size.
If this overflows, the size and other information will be listed on a
separate line.
.SH FILES
For each directory, a .desc.pag and .desc.dir (DBM files) are used to
store descriptions.
.SH SEE\ ALSO
ls(1), describe(1).
SHAR_EOF
chmod 0640 dls.man ||
echo 'restore of dls.man failed'
Wc_c="`wc -c < 'dls.man'`"
test 1774 -eq "$Wc_c" ||
	echo 'dls.man: original size 1774, current size' "$Wc_c"
rm -f _shar_wnt_.tmp
fi
# ============= describe.man ==============
if test -f 'describe.man' -a X"$1" != X"-c"; then
	echo 'x - skipping describe.man (File already exists)'
	rm -f _shar_wnt_.tmp
else
> _shar_wnt_.tmp
echo 'x - extracting describe.man (Text)'
sed 's/^X//' << 'SHAR_EOF' > 'describe.man' &&
.\" describe.man -	Man page for describe
.\"
.\" Copyright (c) 1991 Tim Cook.
.\" Non-profit distribution allowed.  See README for details.
.\"
.\" $Header: describe.man 1.0 91/03/22 $
.\"
.TH DESCRIBE 1 "20 March, 1991"
.UC 4
.SH NAME
describe - Set or list a descriptive comment for a file
.SH SYNOPSIS
.B describe file description
.PP
.B describe -s descriptions-file
[
directory
]
.PP
.B describe -d file ...
.PP
.B describe -l
[
directory
]
.SH DESCRIPTION
.I Describe
sets, deletes or lists file descriptions, as used by the
.I dls
utility.
To set the description on one file, use the first form shown above.
To set descriptions on a number of files, put the descriptions into a file,
then use the -s option as shown above
(leaving off
.I directory
implies the current directory).  If you use a hyphen (-) as the name of the
descriptions file,
.I describe
will read standard input for the list of descriptions.
To delete the description for one or more files, use the -d option as shown
above.
To list all the descriptions set for files in a directory, use the -l option
(again, leaving off
.I directory
means the current directory).
.PP
A description-file is a simple text file.
Each line should list the file name (quoted with double quotes if it
contains white-space), followed by white-space, followed by the
description.
The description itself may contain white-space, and is only terminated
by an end-of-line.
Comments may appear in a description file, as a line that starts with a
hash (#) character.
.PP
Descriptions are stored in DBM files.
Each description is keyed by the file name, and the file name is also
keyed by the file's inode-number.
This means that renaming or editing the file in the same directory will
not mean the loss of its description.
If you wish to ``optimize'' the description database of a directory,
you can do so in the following manner:
.PP
.nf
X	% describe -l > /tmp/descriptions
X	% rm .desc.*
X	% describe -s /tmp/descriptions
.fi
.SH FILES
For each directory, a .desc.pag and .desc.dir (DBM files) are used to
store descriptions.
.SH SEE\ ALSO
dls(1).
SHAR_EOF
chmod 0640 describe.man ||
echo 'restore of describe.man failed'
Wc_c="`wc -c < 'describe.man'`"
test 2094 -eq "$Wc_c" ||
	echo 'describe.man: original size 2094, current size' "$Wc_c"
rm -f _shar_wnt_.tmp
fi
# ============= strpbrk.c ==============
if test -f 'strpbrk.c' -a X"$1" != X"-c"; then
	echo 'x - skipping strpbrk.c (File already exists)'
	rm -f _shar_wnt_.tmp
else
> _shar_wnt_.tmp
echo 'x - extracting strpbrk.c (Text)'
sed 's/^X//' << 'SHAR_EOF' > 'strpbrk.c' &&
/*
X * Copyright (c) 1985 Regents of the University of California.
X * All rights reserved.
X *
X * Redistribution and use in source and binary forms are permitted
X * provided that the above copyright notice and this paragraph are
X * duplicated in all such forms and that any documentation,
X * advertising materials, and other materials related to such
X * distribution and use acknowledge that the software was developed
X * by the University of California, Berkeley.  The name of the
X * University may not be used to endorse or promote products derived
X * from this software without specific prior written permission.
X * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
X * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
X * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE.
X */
X
#if defined(LIBC_SCCS) && !defined(lint)
static char sccsid[] = "@(#)strpbrk.c	5.5 (Berkeley) 5/10/89";
#endif /* LIBC_SCCS and not lint */
X
char *
strpbrk(s1, s2)
X	register char *s1, *s2;
{
X	register int c, sc;
X	register char *scanp;
X
X	for (; c = *s1; ++s1)
X		for (scanp = s2; sc = *scanp++;)
X			if (sc == c)
X				return(s1);
X	return(0);
}
SHAR_EOF
chmod 0640 strpbrk.c ||
echo 'restore of strpbrk.c failed'
Wc_c="`wc -c < 'strpbrk.c'`"
test 1162 -eq "$Wc_c" ||
	echo 'strpbrk.c: original size 1162, current size' "$Wc_c"
rm -f _shar_wnt_.tmp
fi
# ============= perror2.c ==============
if test -f 'perror2.c' -a X"$1" != X"-c"; then
	echo 'x - skipping perror2.c (File already exists)'
	rm -f _shar_wnt_.tmp
else
> _shar_wnt_.tmp
echo 'x - extracting perror2.c (Text)'
sed 's/^X//' << 'SHAR_EOF' > 'perror2.c' &&
/* perror2 -	Like perror(3), but with two string prefixes
X *
X * SYNOPSIS
X *	void perror2 (const char *str1, const char *str2) ;
X *
X * DESCRIPTION
X *	Prints str1, then a colon and a space, then str2, then a colon and
X *	a space, then the error message corresponding to the contents of
X *	errno, then a newline on stderr.
X */
X
static char rcsid[] = "$Header: perror2.c 1.1 91/03/22 $" ;
X
extern int strlen () ;
X
X
void perror2 (str1, str2)
X   char *str1, *str2 ;
{
X   extern int errno ;
X   extern char *sys_errlist[] ;
X   extern int sys_nerr ;
X   register int save_errno = errno ;
X   static char unknown_error[] = "Unknown error" ;
X   static char colon_space[2] = {':', ' '} ;
X   static char newline = '\n' ;
X   char *p ;
X
X   if (save_errno < 0 || save_errno >= sys_nerr)
X      p = unknown_error ;
X   else
X      p = sys_errlist[save_errno] ;
X   write (2, str1, strlen (str1)) ;
X   write (2, colon_space, sizeof (colon_space)) ;
X   write (2, str2, strlen (str2)) ;
X   write (2, colon_space, sizeof (colon_space)) ;
X   write (2, p, strlen (p)) ;
X   write (2, &newline, 1) ;
X   }
X
X
#ifdef TEST
X
int main (argc, argv)
X   int argc ;
X   char **argv ;
{
X   extern int errno ;
X
X   errno = atoi (argv[1]) ;
X   perror2 (argv[2], argv[3]) ;
X   exit (1) ;
X   }
X
#endif	/* TEST */
SHAR_EOF
chmod 0640 perror2.c ||
echo 'restore of perror2.c failed'
Wc_c="`wc -c < 'perror2.c'`"
test 1265 -eq "$Wc_c" ||
	echo 'perror2.c: original size 1265, current size' "$Wc_c"
rm -f _shar_wnt_.tmp
fi
rm -f _shar_seq_.tmp
echo You have unpacked the last part
exit 0