list - Prints documented listings (C version - fast)

Christian Schlichtherle chris at attron.ruhr.sub.org
Tue Feb 5 08:17:04 AEST 1991


This is a quick and dirty rehack of my "list" shellscript I posted before.
The source code is not elegant at all, but the program is very _fast_!
The bigger the directory, the faster it is in relation to "ls". Yes, it is
even faster!
Also, this version is more verbose than the old shell script. You can
print the owner, group and last modification date of the file now. You
can even use one description list for several directories...

Chris
P.S.: Enjoy it!

#!/bin/sh
# This is a shell archive (shar 3.24)
# made 02/04/1991 21:15 UTC by chris at attron.ruhr.sub.org
# Source directory /u/chris/src/list
#
# existing files WILL be overwritten
#
# This shar contains:
# length  mode       name
# ------ ---------- ------------------------------------------
#    209 -rw-r----- .list
#    539 -r--r----- Makefile
#   2447 -r--r----- README
#    379 -r--r----- config.h
#  19228 -r--r----- list.c
#
if touch 2>&1 | fgrep '[-amc]' > /dev/null
 then TOUCH=touch
 else TOUCH=true
fi
# ============= .list ==============
echo "x - extracting .list (Text)"
sed 's/^X//' << 'SHAR_EOF' > .list &&
X.		This directory
X.list		Description list for this directory
XMakefile	Makefile for list(C)
XREADME		Documentation file for list(C)
Xconfig.h	Some configurable parameters for list(C)
Xlist.c		C Source for list(C)
SHAR_EOF
$TOUCH -am 0204210891 .list &&
chmod 0640 .list ||
echo "restore of .list failed"
set `wc -c .list`;Wc_c=$1
if test "$Wc_c" != "209"; then
	echo original size 209, current size $Wc_c
fi
# ============= Makefile ==============
echo "x - extracting Makefile (Text)"
sed 's/^X//' << 'SHAR_EOF' > Makefile &&
X#
X#	@(#) Makefile	1.1 91/02/04 
X#
X#	Author: Christian Schlichtherle, 1991
X#		(chris at attron.ruhr.sub.org)
X#
X#	Makefile - Makefile for list(C).
X#
X
XBIN = /u/bin
XOWNER = chris
XGROUP = freak
XMODE = 0711
X
XCC = cc
XCFLAGS = -Ml2 -i
XLDFLAGS = -s
X
XSHELL = /bin/sh
X
XOBJS = list.o
X
Xlist: list.o
X	$(CC) $(CFLAGS) $(LDFLAGS) -o $@ list.o
X
Xlist.o: config.h
X
Xinstall: $(BIN)/list
X
X$(BIN)/list: list
X	cp $? $@
X	chown $(OWNER) $@
X	chgrp $(GROUP) $@
X	chmod $(MODE) $@
X
Xuninstall:
X	rm -f $(BIN)/list
X
Xclean:
X	rm -f a.out core *.o
X
Xclobber: clean
X	rm -f list
X
SHAR_EOF
$TOUCH -am 0204221191 Makefile &&
chmod 0440 Makefile ||
echo "restore of Makefile failed"
set `wc -c Makefile`;Wc_c=$1
if test "$Wc_c" != "539"; then
	echo original size 539, current size $Wc_c
fi
# ============= README ==============
echo "x - extracting README (Text)"
sed 's/^X//' << 'SHAR_EOF' > README &&
XThis is a quick and dirty rehack of my "list" shellscript I posted before.
XThe source code is not elegant at all, but the program is very _fast_!
XThe bigger the directory, the faster it is in relation to "ls". Yes, it is
Xeven faster!
XAlso, this version is more verbose than the old shell script. You can
Xprint the owner, group and last modification date of the file now. You
Xcan even use one description list for several directories...
X
X
X	@(#) README	1.1 91/02/04 
X
X	Author: Christian Schlichtherle, 1991
X		(chris at attron.ruhr.sub.org)
X
X	README - Documentation file for list(C).
X
X
XNAME
X
X	list - Prints documented listings.
X
X
XSYNTAX
X
X	list [-s] [-a|-A] [-ugd] [-l <listpath>] [<pathname>] ...
X	list -U [-k] [-l <listpath>] [<directory>] ...
X
X
XDESCRIPTION
X
X	list(C) prints a documented listing on standard output. The
X	output is formatted. The first field contains the size of the
X	file in bytes and the second field the filename. The rest of
X	the line contains the description for the file. The lines
X	are sorted in increasing ASCII collating sequence (like
X	ls(C)).
X	The description for the files is held in the file ".list"
X	in the directory where the files reside. This file is
X	formatted as follows: The first field contains the filename
X	and the rest of the line contains the description for the
X	file. The lines are sorted in increasing ASCII collating
X	sequence.
X
X	Options:
X
X	-s	Sorts the description lines found in ".list" before
X		listing the files. This is useful if your ".list"
X		file isn't sorted already.
X	-A	Lists filenames beginning with a period for non
X		superusers, too.
X	-a	Lists all valid entries found in the directory.
X	-u	Prints the owner (user) of the file, too.
X	-g	Prints the group of the file, too.
X	-d	Prints the date of last modification to the file,
X		too.
X	-l name	Overrides the default filename of the description 
X		list ".list". You can use any valid pathname.
X
X	The second form of the command 'list -U [<directory> ...]'
X	updates the ".list" file. The lines are sorted, descriptions
X	for nonexistent files are thrown away and the output is
X	formatted.
X
X	Options:
X
X	-k	Keeps the description file if it is empty after
X		updating. Normally the file is removed if it is
X		empty after updating.
X	-l name	Overrides the default filename of the description 
X		list ".list". You can use any valid pathname.
X		The update is made to this file instead of the
X		default ".list".
X
X
XFILES
X	
X	.list		Description file for listing
SHAR_EOF
$TOUCH -am 0204221191 README &&
chmod 0440 README ||
echo "restore of README failed"
set `wc -c README`;Wc_c=$1
if test "$Wc_c" != "2447"; then
	echo original size 2447, current size $Wc_c
fi
# ============= config.h ==============
echo "x - extracting config.h (Text)"
sed 's/^X//' << 'SHAR_EOF' > config.h &&
X/*
X * @(#) config.h  1.1	91/02/04 
X *
X * Author: Christian Schlichtherle, 1991
X *	   (chris at attron.ruhr.sub.org)
X *
X * config.h - C include file	for list(C).
X */
X
X   /* Default name of the description file */
X#define	LISTFILE     ".list"
X
X   /* Things you normally won't	change */
X#define	TABLEN	     8
X#define	PATHLEN	     255
X#define	LINELEN	     255
X#define	MEMBLKSIZ    1024
SHAR_EOF
$TOUCH -am 0204221191 config.h &&
chmod 0440 config.h ||
echo "restore of config.h failed"
set `wc -c config.h`;Wc_c=$1
if test "$Wc_c" != "379"; then
	echo original size 379, current size $Wc_c
fi
# ============= list.c ==============
echo "x - extracting list.c (Text)"
sed 's/^X//' << 'SHAR_EOF' > list.c &&
X/*
X * @(#) list.c  1.1	91/02/04 
X *
X * Author: Christian Schlichtherle, 1991
X *	   (chris at attron.ruhr.sub.org)
X *
X * list.c - C module for list(C).
X */
X
X#if   !defined(lint) &&	!defined(library)
Xstatic char sccsid[] = "@(#) list.c 1.1 91/02/04 ";
X#endif /* not lint and not library */
X
X#include <stdio.h>
X#include <ctype.h>
X#include <string.h>
X#include <time.h>
X#include <sys/types.h>
X#include <sys/stat.h>
X#include <sys/dir.h>
X#include <malloc.h>
X#include <errno.h>
X#include <pwd.h>
X#include <grp.h>
X#include <search.h>
X#include "config.h"
X
Xchar  *month[] = {
X   "Jan",
X   "Feb",
X   "Mar",
X   "Apr",
X   "May",
X   "Jun",
X   "Jul",
X   "Aug",
X   "Sep",
X   "Oct",
X   "Nov",
X   "Dec"
X};
Xchar  *usage_txt[] = {
X   "usage:\t%s [-s] [-a|-A] [-ugd] [-l <listpath>] [<pathname>] ...\n",
X   "\t%s -U [-k] [-l <listpath>] [<directory>] ...\n"
X};
X
Xextern void perror();
Xextern int  getopt();
Xextern void exit();
Xextern void qsort();
Xextern char *bsearch();
Xextern struct passwd *getpwent();
Xextern struct group  *getgrent();
Xextern long time();
X
Xchar  *progname;
Xint   update = 0;
Xchar  *multicast = NULL;
Xenum  {	simple,	all, allbutdot } listmode = simple;
Xint   KeepEmptyList = 0;
Xint   SortBeforeList = 0;
Xint   PrintOwner = 0;
Xint   PrintGroup = 0;
Xint   PrintDate	= 0;
X
X/*
X * error - Prints an error message.
X * The first argument (if not NULL) is printed using perror(),
X * the second argument is printed on standard error.
X */
Xvoid  error(err1, err2)
Xchar  *err1, *err2;
X{
X   if ((err1 ||	err2) && !isatty(0))
X      (void) fprintf(stderr, "%s: ", progname);
X   if (err1)
X      perror(err1);
X   if (err2)
X      (void) fprintf(stderr, "%s\n", err2);
X
X   return;
X}
X
X/*
X * usage - Prints usage	and exits.
X */
Xvoid  usage()
X{
X   unsigned i;
X
X   if (!isatty(0))
X      (void) fprintf(stderr, "%s: ", progname);
X   for (i = 0; i < sizeof(usage_txt) / sizeof(usage_txt[0]); i++)
X      (void) fprintf(stderr, usage_txt[i], progname);
X
X   exit(1);
X}
X
X/*
X * fatal - Prints an error message using error() and exits.
X */
Xvoid  fatal(err1, err2)
Xchar  *err1, *err2;
X{
X   error(err1, err2);
X
X   exit(1);
X   return;
X}
X
X/*
X * FormatLines - Formats lines in order	to update the description file.
X */
Xvoid	 FormatLines(linesc, lines)
Xunsigned linesc;
Xchar	 **lines;
X{
X   char	 buf[LINELEN + 1];
X   char	 *ptr;
X   char	 *lptr;
X
X#ifdef	 DEBUG
X   (void) fputs("Formating some lines...\n", stderr);
X#endif
X   buf[LINELEN]	= '\0';
X   while (linesc--)
X   {
X      ptr = buf;
X      lptr = lines[linesc];
X
X      while (isspace(*lptr))	 /* Skip any leading blanks in source */
X	 lptr++;
X      while (!isspace(*lptr))	 /* Extract filename to	destination */
X	 *ptr++	= *lptr++;
X      while (isspace(*lptr))	 /* Skip further blanks	in source */
X	 lptr++;
X      *ptr++ = '\t';		 /* Append an appropriate number of tabs */
X      if (ptr -	buf <= TABLEN)
X	 *ptr++	= '\t';
X	    /* Copy the	rest of	the line */
X      (void) strncpy(ptr, lptr,	LINELEN	- (ptr - buf));
X
X      (void) free(lines[linesc]);
X      if ((lines[linesc] = strdup(buf))	== NULL)
X	 fatal(NULL, "Out of memory");
X   }
X
X   return;
X}
X
X/*
X * skipword - Skips the	next word in the string.
X * Returns NULL	if there is no word after the next word.
X */
Xchar  *skipword(s)
Xchar  *s;
X{
X   while (isspace(*s))
X      s++;
X   while (*s &&	!isspace(*s))
X      s++;
X   while (isspace(*s))
X      s++;
X   if (*s)
X      return s;
X
X   return NULL;
X}
X
X/*
X * wrdcmp - Compares the first word in each string with	each other.
X */
Xint   wrdcmp(s1, s2)
Xchar  **s1, **s2;
X{
X   char	 *p1 = *s1, *p2	= *s2;
X
X   while (isspace(*p1))
X      p1++;
X   while (isspace(*p2))
X      p2++;
X   while (*p1 && *p1 ==	*p2 && !isspace(*p1) &&	!isspace(*p2))
X      p1++, p2++;
X
X   if (isspace(*p1))
X      if (isspace(*p2))
X	 return	0;
X      else
X	 return	-*p2;
X   else
X      if (isspace(*p2))
X	 return	*p1;
X      else
X	 return	*p1 - *p2;
X}
X
X/*
X * SortLines - Sorts some lines.
X * Only	the first word is used for sorting.
X */
Xvoid	 SortLines(linesc, lines)
Xunsigned linesc;
Xchar	 **lines;
X{
X#ifdef	 DEBUG
X   (void) fputs("Sorting some lines...\n", stderr);
X#endif
X   qsort((char *) lines, linesc, sizeof(*lines), wrdcmp);
X
X   return;
X}
X
X/*
X * FreeLines - Frees previously	allocated lines	by AddMem().
X */
Xvoid	 FreeLines(listc, list)
Xunsigned *listc;
Xchar	 ***list;
X{
X   if (*listc != 0)
X   {
X      while (*listc != 0)
X	 free((*list)[--(*listc)]);
X      if (*list	!= (char **) 0)
X	 free((char *) *list);
X      *listc = 0;
X      *list = (char **)	0;
X   }
X
X   return;
X}
X
X/*
X * isdir - Checks if "path" is a directory.
X */
Xint   isdir(path)
Xchar  *path;
X{
X   struct stat st;
X
X   if (stat(path, &st) == -1)
X      return 0;
X   if (st.st_mode & 040000)
X      return 1;
X
X   return 0;
X}
X
X/*
X * BuildListpath - Builds the path of the description file used	for listing.
X */
Xvoid  BuildListpath(path, isadir, listpath)
Xchar  *path;
Xint   isadir;
Xchar  *listpath;
X{
X   extern char *multicast;
X   char	       *ptr;
X
X   if (multicast)
X      (void) strcpy(listpath, multicast);
X   else
X      if (isadir)
X	 (void)	sprintf(listpath, "%s/%s", path, LISTFILE);
X      else
X	 if ((ptr = strrchr(path, '/'))	!= NULL)
X	 {
X	    (void) strncpy(listpath, path, ptr - path +	1);
X	    listpath[ptr - path	+ 2] = '\0';
X	    (void) strcat(listpath, LISTFILE);
X	 }
X	 else
X	    (void) strcpy(listpath, LISTFILE);
X
X   return;
X}
X
X/*
X * AddMem - Adds memory	(if needed) to hold some data.
X * Memory is added in MEMBLKSIZ	blocks of bytes.
X */
Xvoid	 AddMem(nel, ptr, width)
Xunsigned nel;
Xchar	 **ptr;
Xunsigned width;
X{
X   unsigned blksiz = MEMBLKSIZ / width * width;
X
X   if (!(nel * width % blksiz) || !*ptr)
X      if (!nel || !*ptr)
X      {
X	 if ((*ptr = malloc(blksiz)) ==	NULL)
X	    fatal(NULL,	"Out of memory");
X      }
X      else
X	 if ((*ptr = realloc(*ptr, (nel	+ MEMBLKSIZ / width) * width))
X	     ==	NULL)
X	    fatal(NULL,	"Out of memory");
X
X   return;
X}
X
X/*
X * ReadFile - Reads a file using "inpfnc()".
X */
Xint	 ReadFile(path,	listc, list, inpfnc)
Xchar	 *path;
Xunsigned *listc;
Xchar	 ***list;
Xchar	 *(*inpfnc)();
X{
X   FILE	 *fp;
X   char	 *line;
X
X   if ((fp = fopen(path, "r")) == (FILE	*) 0)
X      return -1;
X   while ((line	= (*inpfnc)(fp)) != NULL)
X   {
X      AddMem(*listc, (char **) list, sizeof(char *));
X      if (((*list)[(*listc)++] = strdup(line)) == NULL)
X	 fatal(NULL, "Out of memory");
X   }
X   (void) fclose(fp);
X
X   return 0;
X}
X
X/*
X * flistentry -	Reads a	single line of a description file.
X */
Xchar  *flistentry(fp)
XFILE  *fp;
X{
X   static char buf[LINELEN + 1];
X
X      /* Read lines until a line contains more than the	filename */
X   while (fgets(buf, LINELEN + 1, fp) != NULL)
X      if (skipword(buf))
X	 return	buf;
X
X   return NULL;
X}
X
X/*
X * ReadList - Reads description	file.
X */
Xvoid	 ReadList(listpath, listc, list)
Xchar	 *listpath;
Xunsigned *listc;
Xchar	 ***list;
X{
X#ifdef	 DEBUG
X   (void) fprintf(stderr, "Reading description list \"%s\"...\n", listpath);
X#endif
X
X   (void) ReadFile(listpath, listc, list, flistentry);
X   return;
X}
X
X/*
X * fdirentry - Reads a single directory	entry.
X */
Xchar  *fdirentry(fp)
XFILE  *fp;
X{
X   static char	  buf[DIRSIZ + 1];
X   struct direct  dir;
X
X   buf[DIRSIZ] = '\0';
X
X   while (fread((char *) &dir, sizeof(dir), 1, fp) == 1)
X   {
X      if (dir.d_ino == 0)
X	 continue;
X      (void) strncpy(buf, dir.d_name, DIRSIZ);
X      if (update)
X	 return	buf;
X      switch (listmode)
X      {
X	 case simple:
X	    if (buf[0] != '.')
X	       return buf;
X	    break;
X	 case all:
X	    return buf;
X	 case allbutdot:
X	    if (strcmp(buf, ".") && strcmp(buf,	".."))
X	       return buf;
X      }
X   }
X
X   return NULL;
X}
X
X/*
X * ReadDir - Reads a directory.
X */
Xint	 ReadDir(dirpath, dirc,	dir)
Xchar	 *dirpath;
Xunsigned *dirc;
Xchar	 ***dir;
X{
X   struct stat st;
X
X#ifdef	 DEBUG
X   (void) fprintf(stderr, "Reading directory \"%s\"...\n", dirpath);
X#endif
X
X   if (stat(dirpath, &st) == -1)
X   {
X      error(dirpath, NULL);
X      return -1;
X   }
X   errno = 0;
X   if (!(st.st_mode & 040000))
X      errno = ENOTDIR;
X   if (!errno)
X      (void) access(dirpath, 01);
X   if (errno)
X      error(dirpath, NULL);
X   return ReadFile(dirpath, dirc, dir, fdirentry);
X}
X
X/*
X * uidcmp - Compares user ids.
X */
Xint	       uidcmp(pw1, pw2)
Xstruct passwd  *pw1, *pw2;
X{
X   return pw1->pw_uid -	pw2->pw_uid;
X}
X
X/*
X * ReadEtcPasswd - Reads /etc/passwd file.
X */
Xvoid	       ReadEtcPasswd(pw_c, pw_v)
Xunsigned       *pw_c;
Xstruct passwd  **pw_v;
X{
X   struct passwd  *pw;
X   unsigned	  old_c;
X
X#ifdef	 DEBUG
X   (void) fputs("Reading password entries...\n", stderr);
X#endif
X   *pw_c = 0;
X   *pw_v = (struct passwd *) 0;
X   while ((pw =	getpwent()) != (struct passwd *) 0)
X   {
X      AddMem(*pw_c, (char **) pw_v, sizeof(struct passwd));
X      old_c = *pw_c;
X      (void) lsearch((char *) pw, (char	*) *pw_v, pw_c,	sizeof(struct passwd),
X		     uidcmp);
X      if (*pw_c	> old_c)
X	 if (((*pw_v)[*pw_c - 1].pw_name = strdup(pw->pw_name))	== NULL)
X	    fatal(NULL,	"Out of memory");
X   }
X   qsort((char *) *pw_v, *pw_c,	sizeof(struct passwd), uidcmp);
X
X   return;
X}
X
X/*
X * gidcmp - Compares two group ids.
X */
Xint	       gidcmp(gr1, gr2)
Xstruct group   *gr1, *gr2;
X{
X   return gr1->gr_gid -	gr2->gr_gid;
X}
X
X/*
X * ReadEtcGroup	- Reads	/etc/group file.
X */
Xvoid	       ReadEtcGroup(gr_c, gr_v)
Xunsigned       *gr_c;
Xstruct group   **gr_v;
X{
X   struct group	  *gr;
X   unsigned	  old_c;
X
X#ifdef	 DEBUG
X   (void) fputs("Reading group entries...\n", stderr);
X#endif
X   *gr_c = 0;
X   *gr_v = (struct group *) 0;
X   while ((gr =	getgrent()) != (struct group *)	0)
X   {
X      AddMem(*gr_c, (char **) gr_v, sizeof(struct group));
X      old_c = *gr_c;
X      (void) lsearch((char *) gr, (char	*) *gr_v, gr_c,	sizeof(struct group),
X		     gidcmp);
X      if (*gr_c	> old_c)
X	 if (((*gr_v)[*gr_c - 1].gr_name = strdup(gr->gr_name))	== NULL)
X	    fatal(NULL,	"Out of memory");
X   }
X   qsort((char *) *gr_v, *gr_c,	sizeof(struct group), gidcmp);
X
X   return;
X}
X
X/*
X * ListFile - Prints a documented listing of a file.
X * If "isadir" is a directory "path/file" is used for listing, "path"
X * otherwise.
X * "pw_c" is the number	of struct passwd entries in "pw_v".
X * "gr_c" is the number	of struct group	entries	in "gr_v".
X * "ActMonth" is the number of Months since 1900. This is used to determine
X * the output format of	the last modification date of the file.
X * "desc" is the descriptive text for the file.	It must	end with a
X * newline.
X */
Xint	       ListFile(path, isadir, file, pw_c, pw_v,	gr_c, gr_v, ActMonth,
X			desc)
Xchar	       *path;
Xint	       isadir;
Xchar	       *file;
Xunsigned       pw_c;
Xstruct passwd  *pw_v;
Xunsigned       gr_c;
Xstruct group   *gr_v;
Xint	       ActMonth;
Xchar	       *desc;
X{
X   char			buf[PATHLEN + 1];
X   struct stat		st;
X   struct passwd	*pw, pw_dummy;
X   struct group		*gr, gr_dummy;
X   long			htime;
X   struct tm		*tm;
X
X   if (isadir)
X      (void) sprintf(buf, "%s/%s", path, file);
X   else
X      (void) strcpy(buf, path);
X   if (stat(buf, &st) == -1)
X   {
X      error(buf, NULL);
X      return -1;
X   }
X   if (PrintOwner && pw_c)
X   {
X      pw_dummy.pw_uid =	st.st_uid;
X      pw = (struct passwd *) bsearch((char *) &pw_dummy, (char *) pw_v,	pw_c,
X				     sizeof(struct passwd), uidcmp);
X      if (pw !=	(struct	passwd *) 0)
X	 (void)	printf("%-8s ",	pw->pw_name);
X   }
X   if (PrintGroup && gr_c)
X   {
X      gr_dummy.gr_gid =	st.st_gid;
X      gr = (struct group *) bsearch((char *) &gr_dummy,	(char *) gr_v, gr_c,
X				    sizeof(struct group), gidcmp);
X      if (gr !=	(struct	group *) 0)
X	 (void)	printf("%-8s ",	gr->gr_name);
X   }
X   (void) printf("%7lu ", (unsigned long) st.st_size);
X   if (PrintDate)
X   {
X      htime = (long) st.st_mtime;
X      tm = localtime(&htime);
X      (void) printf("%s %2d ", month[tm->tm_mon], tm->tm_mday);
X      if (abs(ActMonth - (12 * tm->tm_year + tm->tm_mon)) > 6)
X	 (void)	printf("%5d ", 1900 + tm->tm_year);
X      else
X	 (void)	printf("%02d:%02d ", tm->tm_hour, tm->tm_min);
X   }
X   (void) printf("%-14s", file);
X   if (desc)
X      (void) printf(" %s", desc);
X   else
X      (void) putchar('\n');
X
X   return 0;
X}
X
X/*
X * join	- Joins	the description	list and the directory entries in
X * order to print a documented listing.
X * "path" is the pathname of the file or directory to list.
X * "isadir" tells you, if "path" is a directory.
X * "listpath" is the pathname of the description list.
X * Rest	is in "ListFile()".
X */
Xint	       join(path, isadir, listpath, dirc, dir, listc, list, pw_c, pw_v,
X		    gr_c, gr_v,	ActMonth)
Xchar	       *path;
Xint	       isadir;
Xchar	       *listpath;
Xunsigned       dirc;
Xchar	       **dir;
Xunsigned       listc;
Xchar	       **list;
Xunsigned       pw_c;
Xstruct passwd  *pw_v;
Xunsigned       gr_c;
Xstruct group   *gr_v;
Xint	       ActMonth;
X{
X   FILE		  *fp;
X   unsigned	  i, j;
X   int		  diff;
X   int		  EmptyList = 1;
X   char		  *ptr;
X
X#ifdef	 DEBUG
X   if (update)
X      (void) fprintf(stderr, "Joining and updating \"%s\"\n", listpath);
X   else
X      (void) fprintf(stderr, "Joining and listing from \"%s\"...\n", listpath);
X#endif
X
X   if (update)
X   {
X      if ((fp =	fopen(listpath,	"w")) == (FILE *) 0)
X      {
X	 (void)	fprintf(stderr,	"Cannot open \"%s\" for writing\n", listpath);
X	 return	-1;
X      }
X   }
X   i = 0;
X   j = 0;
X   while (i < dirc && (!update || j < listc))
X   {
X      if (j < listc)
X	 if (diff = wrdcmp(&dir[i], &list[j]))
X	    ptr	= NULL;
X	 else
X	    ptr	= skipword(list[j]);
X      else
X      {
X	 diff =	-1;
X	 ptr = NULL;
X      }
X      if (update)
X      {
X	 if (!diff)
X	 {
X	    EmptyList =	0;
X	    if (fputs(list[j], fp) == EOF)
X	    {
X	       (void) fprintf(stderr, "Can't write to file \"%s\"\n",
X			      listpath);
X	       break;
X	    }
X#ifdef	 DEBUG
X	    (void) fputs(list[j], stderr);
X#endif
X	 }
X      }
X      else
X	 if (diff <= 0
X	     &&	ListFile(path, isadir, dir[i], pw_c, pw_v, gr_c, gr_v,
X			 ActMonth, ptr)	== -1)
X	    return -1;
X      if (diff <= 0)
X	 i++;
X      if (diff >= 0)
X	 j++;
X   }
X   if (update)
X   {
X      (void) fclose(fp);
X      if (EmptyList)
X	 if (!KeepEmptyList)
X	 {
X#ifdef	 DEBUG
X	    (void) fputs("Description list is empty - removing it\n", stderr);
X#endif
X	    if (unlink(listpath) == -1)	{
X	       error(listpath, "Cannot remove empty description list");
X	       return -1;
X	    }
X	 }
X#ifdef	 DEBUG
X	 else
X	    (void) fputs("Description list is empty - keeping it\n", stderr);
X#endif
X   }
X
X   return 0;
X}
X
X/*
X * ProcessPaths	- Processes (lists or updates) all paths.
X */
Xint   ProcessPaths(pathc, pathv)
Xint   pathc;
Xchar  **pathv;
X{
X   int		  i;
X   int		  err =	0;
X   unsigned	  listc	= 0;
X   char		  **list = (char **) 0;
X   unsigned	  dirc = 0;
X   char		  **dir	= (char	**) 0;
X   char		  listpath[PATHLEN + 1];
X   int		  isadir;
X   int		  sorted = 0;
X   long		  htime;
X   struct tm	  *tm;
X   unsigned	  pw_c;
X   struct passwd  *pw_v;
X   unsigned	  gr_c;
X   struct group	  *gr_v;
X   int		  ActMonth;
X
X   if (PrintOwner)
X      ReadEtcPasswd(&pw_c, &pw_v);
X   if (PrintGroup)
X      ReadEtcGroup(&gr_c, &gr_v);
X   if (PrintDate)
X   {
X      (void) time(&htime);
X      tm = localtime(&htime);
X      ActMonth = 12 * tm->tm_year + tm->tm_mon;
X   }
X   if (multicast)
X   {
X#ifdef	 DEBUG
X      (void) fputc('\n', stderr);
X#endif
X      if (update && access(multicast, 06) == -1)
X      {
X	 error(multicast, "Cannot read or write description list");
X	 return	1;
X      }
X      ReadList(multicast, &listc, &list);
X   }
X
X   for (i = 0; i < pathc; i++, pathv++)
X   {
X      isadir = isdir(*pathv);
X      BuildListpath(*pathv, isadir, listpath);
X      if (update)
X      {
X	 if (!isadir)
X	 {
X	    err++;
X	    errno = ENOTDIR;
X	    error(*pathv, NULL);
X	    continue;
X	 }
X      }
X      else
X	 if (isadir && pathc > 1)
X	    (void) printf("\n%s:\n", *pathv);
X      if (!multicast)
X      {
X#ifdef	 DEBUG
X	 (void)	fputc('\n', stderr);
X#endif
X	 if (update && access(listpath,	06) == -1)
X	 {
X	    err++;
X	    error(listpath, "Cannot read or write description list");
X	    continue;
X	 }
X	 ReadList(listpath, &listc, &list);
X      }
X      if (isadir)
X      {
X	 if (ReadDir(*pathv, &dirc, &dir) == -1)
X	 {
X	    if (update || !multicast)
X	    {
X	       FreeLines(&listc, &list);
X	       FreeLines(&dirc,	&dir);
X	    }
X	    if (update && multicast)
X	       return 1;
X	    continue;
X	 }
X      }
X      else
X      {
X	 AddMem(dirc, dir, sizeof(char *));
X	 if ((dir[dirc++] = strdup(*pathv)) == NULL)
X	    fatal(NULL,	"Out of memory");
X      }
X      if (update)
X      {
X	 if (!multicast	|| i ==	pathc -	1)
X	 {
X	    FormatLines(listc, list);
X	    SortLines(listc, list);
X	    SortLines(dirc, dir);
X	    if (join(*pathv, isadir, listpath, dirc, dir, listc, list, pw_c,
X		     pw_v, gr_c, gr_v, ActMonth) == -1)
X	       err++;
X	    FreeLines(&listc, &list);
X	    FreeLines(&dirc, &dir);
X	 }
X      }
X      else
X      {
X	 if (SortBeforeList && (!multicast || !sorted))
X	 {
X	    SortLines(listc, list);
X	    sorted = 1;
X	 }
X	 SortLines(dirc, dir);
X	 if (join(*pathv, isadir, listpath, dirc, dir, listc, list, pw_c,
X		  pw_v,	gr_c, gr_v, ActMonth) == -1)
X	    err++;
X	 FreeLines(&dirc, &dir);
X	 if (!multicast)
X	    FreeLines(&listc, &list);
X      }
X   }
X   if (PrintOwner)
X      free((char *) pw_v);
X   if (PrintGroup)
X      free((char *) gr_v);
X
X   return err;
X}
X
X/*
X * SortPathlist	- Sorts	the paths.
X * Filenames are sorted	first, directories last.
X * Filenames and directories keep their	order of occurence.
X */
Xvoid	 SortPathlist(pathc, pathv)
Xunsigned pathc;
Xchar	 **pathv;
X{
X   int	 i, j, end;
X   char	 *ptr;
X
X   end = pathc;
X   for (i = 0; i < end;	i++)
X      if (isdir(pathv[i]))
X      {
X	 ptr = pathv[i];
X	 for (j	= i; j < pathc - 1; j++)
X	    pathv[j] = pathv[j + 1];
X	 pathv[j] = ptr;
X	 end--;
X      }
X
X   return;
X}
X
X/*
X * BuildPathlist - Builds a list of pathnames to list or update.
X */
Xvoid  BuildPathlist(optind, argc, argv)
Xint   optind;
Xint   *argc;
Xchar  ***argv;
X{
X   static char *def[] =	{  /* Default list of pathnames	*/
X      "."
X   };
X
X   if (optind <	*argc)
X   {
X      *argc = *argc - optind;
X      *argv = &(*argv)[optind];
X      SortPathlist((unsigned) *argc, *argv);
X   }
X   else
X   {
X      *argc = 1;
X      *argv = def;
X   }
X
X   return;
X}
X
Xint   main(argc, argv)
Xint   argc;
Xchar  **argv;
X{
X   extern char *optarg;
X   extern int  optind;
X   int	 c;
X
X   progname = argv[0];
X
X   while ((c = getopt(argc, argv, "?UaAugdksl:")) != EOF)
X      switch(c)
X      {
X      case 'U':
X	 update	= 1;
X	 break;
X      case 'k':
X	 if (!update)
X	    usage();
X	 KeepEmptyList = 1;
X	 break;
X      case 's':
X	 if (update)
X	    usage();
X	 SortBeforeList	= 1;
X	 break;
X      case 'a':
X	 if (update || listmode	!= simple)
X	    usage();
X	 listmode = all;
X	 break;
X      case 'A':
X	 if (update || listmode	!= simple)
X	    usage();
X	 listmode = allbutdot;
X	 break;
X      case 'u':
X	 if (update)
X	    usage();
X	 PrintOwner = 1;
X	 break;
X      case 'g':
X	 if (update)
X	    usage();
X	 PrintGroup = 1;
X	 break;
X      case 'd':
X	 if (update)
X	    usage();
X	 PrintDate = 1;
X	 break;
X      case 'l':
X	 multicast = optarg;
X	 break;
X      default:
X	 usage();
X      }
X   if (!update && listmode == simple &&	!geteuid())
X      listmode = allbutdot;
X
X   BuildPathlist(optind, &argc,	&argv);
X#ifdef	 DEBUG
X   {
X      int   i;
X
X      (void) fputs("Pathnames to list or update:", stderr);
X      for (i = 0; i < argc; i++)
X	 (void)	fprintf(stderr,	" %s", argv[i]);
X      (void) fputc('\n', stderr);
X   }
X#endif	 /* DEBUG */
X   exit(ProcessPaths(argc, argv));
X
X   return 1;
X}
SHAR_EOF
$TOUCH -am 0204221191 list.c &&
chmod 0440 list.c ||
echo "restore of list.c failed"
set `wc -c list.c`;Wc_c=$1
if test "$Wc_c" != "19228"; then
	echo original size 19228, current size $Wc_c
fi
exit 0
-- 
Snail: Christian Schlichtherle, Elbscheweg 20, 5802 Wetter 4, Germany
Email: chris at attron.ruhr.sub.org	Tel.: +49 2335 7550
"Der Tod ist ein Meister aus Deutschland" -- Paul Celan



More information about the Alt.sources mailing list