Fast Printer driver
Tom Neff
tneff at bfmny0.BFM.COM
Fri Jul 27 15:18:35 AEST 1990
In article <1990Jul26.015350.1481 at cimcor.mn.org> mike at cimcor.mn.org (Michael Grenier) writes:
>Sorry, about the tar file...my shar doesn't understand directories.
Fix it.
#! /bin/sh
# This is a shell archive, meaning:
# 1. Remove everything above the #! /bin/sh line.
# 2. Save the resulting text in a file.
# 3. Execute the file with /bin/sh (not csh) to create:
# getopt.3
# getopt.c
# makefile
# shar.1
# shar.c
# traverse.3
# traverse.c
# This archive created: Fri Jul 27 11:13:30 1990
export PATH; PATH=/bin:/usr/bin:$PATH
if test -f 'getopt.3'
then
echo shar: "will not over-write existing file 'getopt.3'"
else
sed 's/^X//' << \SHAR_EOF > 'getopt.3'
X.TH GETOPT 3 local
X.DA 25 March 1982
X.SH NAME
Xgetopt \- get option letter from argv
X.SH SYNOPSIS
X.ft B
Xint getopt(argc, argv, optstring)
X.br
Xint argc;
X.br
Xchar **argv;
X.br
Xchar *optstring;
X.sp
Xextern char *optarg;
X.br
Xextern int optind;
X.ft
X.SH DESCRIPTION
X.I Getopt
Xreturns the next option letter in
X.I argv
Xthat matches a letter in
X.IR optstring .
X.I Optstring
Xis a string of recognized option letters;
Xif a letter is followed by a colon, the option is expected to have
Xan argument that may or may not be separated from it by white space.
X.I Optarg
Xis set to point to the start of the option argument on return from
X.IR getopt .
X.PP
X.I Getopt
Xplaces in
X.I optind
Xthe
X.I argv
Xindex of the next argument to be processed.
XBecause
X.I optind
Xis external, it is normally initialized to zero automatically
Xbefore the first call to
X.IR getopt .
X.PP
XWhen all options have been processed (i.e., up to the first
Xnon-option argument),
X.I getopt
Xreturns
X.BR EOF .
XThe special option
X.B \-\-
Xmay be used to delimit the end of the options;
X.B EOF
Xwill be returned, and
X.B \-\-
Xwill be skipped.
X.SH SEE ALSO
Xgetopt(1)
X.SH DIAGNOSTICS
X.I Getopt
Xprints an error message on
X.I stderr
Xand returns a question mark
X.RB ( ? )
Xwhen it encounters an option letter not included in
X.IR optstring .
X.SH EXAMPLE
XThe following code fragment shows how one might process the arguments
Xfor a command that can take the mutually exclusive options
X.B a
Xand
X.BR b ,
Xand the options
X.B f
Xand
X.BR o ,
Xboth of which require arguments:
X.PP
X.RS
X.nf
Xmain(argc, argv)
Xint argc;
Xchar **argv;
X{
X int c;
X extern int optind;
X extern char *optarg;
X \&.
X \&.
X \&.
X while ((c = getopt(argc, argv, "abf:o:")) != EOF)
X switch (c) {
X case 'a':
X if (bflg)
X errflg++;
X else
X aflg++;
X break;
X case 'b':
X if (aflg)
X errflg++;
X else
X bproc();
X break;
X case 'f':
X ifile = optarg;
X break;
X case 'o':
X ofile = optarg;
X break;
X case '?':
X default:
X errflg++;
X break;
X }
X if (errflg) {
X fprintf(stderr, "Usage: ...");
X exit(2);
X }
X for (; optind < argc; optind++) {
X \&.
X \&.
X \&.
X }
X \&.
X \&.
X \&.
X}
X.RE
X.PP
XA template similar to this can be found in
X.IR /usr/pub/template.c .
X.SH HISTORY
XWritten by Henry Spencer, working from a Bell Labs manual page.
XBehavior believed identical to the Bell version.
X.SH BUGS
XIt is not obvious how
X`\-'
Xstanding alone should be treated; this version treats it as
Xa non-option argument, which is not always right.
X.PP
XOption arguments are allowed to begin with `\-';
Xthis is reasonable but reduces the amount of error checking possible.
X.PP
X.I Getopt
Xis quite flexible but the obvious price must be paid: there is much
Xit could do that it doesn't, like
Xchecking mutually exclusive options, checking type of
Xoption arguments, etc.
SHAR_EOF
fi
if test -f 'getopt.c'
then
echo shar: "will not over-write existing file 'getopt.c'"
else
sed 's/^X//' << \SHAR_EOF > 'getopt.c'
X/* got this off net.sources */
X#include <stdio.h>
X
X/*
X * get option letter from argument vector
X */
Xint opterr = 1, /* useless, never set or used */
X optind = 1, /* index into parent argv vector */
X optopt; /* character checked for validity */
Xchar *optarg; /* argument associated with option */
X
X#define BADCH (int)'?'
X#define EMSG ""
X#define tell(s) fputs(*nargv,stderr);fputs(s,stderr); \
X fputc(optopt,stderr);fputc('\n',stderr);return(BADCH);
X
Xgetopt(nargc,nargv,ostr)
Xint nargc;
Xchar **nargv,
X *ostr;
X{
X static char *place = EMSG; /* option letter processing */
X register char *oli; /* option letter list index */
X char *index();
X
X if(!*place) { /* update scanning pointer */
X if(optind >= nargc || *(place = nargv[optind]) != '-' || !*++place) return(EOF);
X if (*place == '-') { /* found "--" */
X ++optind;
X return(EOF);
X }
X } /* option letter okay? */
X if ((optopt = (int)*place++) == (int)':' || !(oli = index(ostr,optopt))) {
X if(!*place) ++optind;
X tell(": illegal option -- ");
X }
X if (*++oli != ':') { /* don't need argument */
X optarg = NULL;
X if (!*place) ++optind;
X }
X else { /* need an argument */
X if (*place) optarg = place; /* no white space */
X else if (nargc <= ++optind) { /* no arg */
X place = EMSG;
X tell(": option requires an argument -- ");
X }
X else optarg = nargv[optind]; /* white space */
X place = EMSG;
X ++optind;
X }
X return(optopt); /* dump back option letter */
X}
SHAR_EOF
fi
if test -f 'makefile'
then
echo shar: "will not over-write existing file 'makefile'"
else
sed 's/^X//' << \SHAR_EOF > 'makefile'
XCFLAGS=-O
Xshar: shar.o traverse.o getopt.o
X cc $(CFLAGS) -o shar shar.o traverse.o getopt.o
X cc -o traverse -DSTANDALONE traverse.c
SHAR_EOF
fi
if test -f 'shar.1'
then
echo shar: "will not over-write existing file 'shar.1'"
else
sed 's/^X//' << \SHAR_EOF > 'shar.1'
X.TH SHAR 1net "June 3, 1985" "UNIX User's Manual" "Wang Institute"
X.SH NAME
Xshar \- create file storage archive for extraction by /bin/sh
X.SH SYNOPSIS
X.B shar
X[-abcsv] [-d delim] [-p prefix] files
X.SH DESCRIPTION
X.I shar
Xprints its input files with special command lines around them
Xto be used by the shell,
X.I /bin/sh ,
Xto extract them later.
XThe output can be filtered through the shell to
Xrecreate copies of the original files.
X.PP
X.I shar
Xallows directories to be named, and
X.I shar
Xprints the necessary commands
X.ul
X(mkdir & cd)
Xto create new directories and fill them.
X.I shar
Xwill emit commands to make executable plain files executable.
X.I shar will not allow existing files to be over-written;
Xsuch files must be removed by the file extractor.
X.SH OPTIONS
X.de OP
X.TP
X.B -\\$1
X..
X.OP a
XAll the options.
XThe options:
X.B "-v -c -b -p <tab>X"
Xare implied.
X.OP s
XSilent running.
XAll checking and extra output is inhibited.
X.OP v
XPrint verbose feedback messages about what
X.I shar
Xis doing to be printed during extraction.
XSizes of plain files are echoed to allow a simple validity check.
X.OP c
XCheck file size on extraction by counting characters.
XAn error message is reported to the person doing the
Xextraction if the sizes don't match.
XOne reason why the sizes may not match is that
X.I shar
Xwill append a newline to complete incomplete last lines;
X.I shar
Xprints a message that mentions added newlines.
XAnother reason why the sizes may not match is that some
Xnetwork mail programs remove non-whitespace control characters.
X.I shar
Xprints a message that mentions control characters to the extractor.
X.OP b
XExtract files into basenames so that files with absolute path names
Xare put into the current directory.
XThis option has strange effects when directories are archived.
X.OP d delim
XUse this as the ``end of file'' delimiter instead of the default.
XThe only reason to change it is if you suspect an file
Xcontains the default delimiter:
X.B SHAR_EOF.
X.OP p prefix
XUse this as the prefix to each line of the archived files.
XThis is to make sure that special characters at the start of lines are not
Xeaten up by programs like mailers.
XIf this option is used,
Xthe files will be extracted with the stream editor
X.B sed
Xrather than
X.B cat
Xso it is more efficient and portable to avoid setting the prefix,
Xthough perhaps less safe if you don't know what is in the files.
X.SH "SEE ALSO
Xtar(1), cpio(1), tp(1), sh(1)
X.SH AUTHOR
XGary Perlman
X(based on a shell version by James Gosling,
Xwith additions motivated by
XDerek Zahn,
XMichael Thompson,
XH. Morrow Long,
XFred Avolio,
XGran Uddeborg,
X&
XChuck Wegrzyn)
X.SH LIMITATIONS
X.I shar
Xdoes not know anything about
Xlinks between files
Xor binary files.
SHAR_EOF
fi
if test -f 'shar.c'
then
echo shar: "will not over-write existing file 'shar.c'"
else
sed 's/^X//' << \SHAR_EOF > 'shar.c'
X#include <stdio.h>
X#include <sys/types.h>
X#include <sys/stat.h>
X#include <ctype.h>
X
X/*{
XShar puts readable text files together in a package
Xfrom which they are easy to extract. The original version
Xwas a shell script posted to the net, shown below:
X #Date: Mon Oct 18 11:08:34 1982
X #From: decvax!microsof!uw-beave!jim (James Gosling at CMU)
X AR=$1
X shift
X for i do
X echo a - $i
X echo "echo x - $i" >>$AR
X echo "cat >$i <<'!Funky!Stuff!'" >>$AR
X cat $i >>$AR
X echo "!Funky!Stuff!" >>$AR
X done
XI rewrote this version in C to provide better diagnostics
Xand to run faster. The major difference is that my version
Xdoes not affect any files because it prints to the standard
Xoutput. Mine also has several options.
X
XGary Perlman/Wang Institute/Tyngsboro, MA/01879/(617) 649-9731
X
XMany enhancements motivated by Michael Thompson.
X
XDirectory archiving motivated by Derek Zahn @ wisconsin
X His version had some problems, so I wrote a general
X routine for traversing a directory hierarchy. It
X allows marching through a directory on old and new
X UNIX systems.
X}*/
X
X/* COMMANDS */
X#define EXTRACT "#! /bin/sh" /* magic exec string at shar file start */
X#define PATH "/bin:$PATH" /* search path for programs */
X#define CAT "cat"; /* /bin/cat */
X#define SED "sed 's/^%s//'" /* /bin/sed removes Prefix from lines */
X#define MKDIR "mkdir" /* make a new dirctory */
X#define CHMOD "chmod +x" /* change file protection (for executables) */
X#define CHDIR "cd" /* change current directory */
X#define TEST "test" /* /bin/test files */
X#define WC_C "wc -c <" /* counts chars in file */
X#define ECHO "echo shar" /* echo a message to extractor */
X
Xmain (argc, argv) char **argv;
X {
X int shar ();
X int optind;
X if ((optind = initial (argc, argv)) < 0)
X exit (1);
X if (header (argc, argv, optind))
X exit (2);
X while (optind < argc)
X traverse (argv[optind++], shar);
X footer ();
X exit (0);
X }
X
X/* OPTIONS */
Xtypedef int lgl;
X#define true ((lgl) 1)
X#define false ((lgl) 0)
Xint Lastchar; /* the last character printed */
Xint Ctrlcount; /* how many bad control characters are in file */
X
X#define USAGE "[-abcsv] [-p prefix] [-d delim] files > archive"
X#define OPTSTRING "abcsvp:d:"
X
Xlgl Verbose = false; /* provide append/extract feedback */
Xlgl Basename = false; /* extract into basenames */
Xlgl Count = false; /* count characters to check transfer */
Xlgl Silent = false; /* turn off all verbosity */
Xchar *Delim = "SHAR_EOF"; /* put after each file */
Xchar Filter[100] = CAT; /* used to extract archived files */
Xchar *Prefix = NULL; /* line prefix to avoid funny chars */
X
Xint /* returns the index of the first operand file */
Xinitial (argc, argv) char **argv;
X {
X int errflg = 0;
X extern int optind;
X extern char *optarg;
X int C;
X while ((C = getopt (argc, argv, OPTSTRING)) != EOF)
X switch (C)
X {
X case 'v': Verbose = true; break;
X case 'c': Count = true; break;
X case 'b': Basename = true; break;
X case 'd': Delim = optarg; break;
X case 's': /* silent running */
X Silent = true;
X Verbose = false;
X Count = false;
X Prefix = NULL;
X break;
X case 'a': /* all the options */
X Verbose = true;
X Count = true;
X Basename = true;
X /* fall through to set prefix */
X optarg = " X";
X case 'p': (void) sprintf (Filter, SED, Prefix = optarg); break;
X default: errflg++;
X }
X if (errflg || optind == argc)
X {
X if (optind == argc)
X fprintf (stderr, "shar: No input files\n");
X fprintf (stderr, "USAGE: shar %s\n", USAGE);
X return (-1);
X }
X return (optind);
X }
X
Xheader (argc, argv, optind)
Xchar **argv;
X {
X int i;
X lgl problems = false;
X long clock;
X char *ctime ();
X char *getenv ();
X char *NAME = getenv ("NAME");
X char *ORG = getenv ("ORGANIZATION");
X for (i = optind; i < argc; i++)
X if (access (argv[i], 4)) /* check read permission */
X {
X fprintf (stderr, "shar: Can't read '%s'\n", argv[i]);
X problems++;
X }
X if (problems) return (problems);
X /* I have given up on putting a cut line in the archive.
X Too many people complained about having to remove it.
X puts ("-----cut here-----cut here-----cut here-----cut here-----");
X */
X puts (EXTRACT);
X puts ("# This is a shell archive, meaning:");
X printf ("# 1. Remove everything above the %s line.\n", EXTRACT);
X puts ("# 2. Save the resulting text in a file.");
X puts ("# 3. Execute the file with /bin/sh (not csh) to create the files:");
X for (i = optind; i < argc; i++)
X printf ("#\t%s\n", argv[i]);
X (void) time (&clock);
X printf ("# This archive created: %s", ctime (&clock));
X if (NAME)
X printf ("# By:\t%s (%s)\n", NAME, ORG ? ORG : "");
X printf ("export PATH; PATH=%s\n", PATH);
X return (0);
X }
X
Xfooter ()
X {
X puts ("#\tEnd of shell archive");
X puts ("exit 0");
X }
X
Xarchive (input, output)
Xchar *input, *output;
X {
X char buf[BUFSIZ];
X FILE *ioptr;
X if (ioptr = fopen (input, "r"))
X {
X if (Count == true)
X {
X Ctrlcount = 0; /* no bad control characters so far */
X Lastchar = '\n'; /* simulate line start */
X }
X printf ("%s << \\%s > '%s'\n", Filter, Delim, output);
X if (Prefix)
X {
X while (fgets (buf, BUFSIZ, ioptr))
X {
X if (Prefix) outline (Prefix);
X outline (buf);
X }
X }
X else copyout (ioptr);
X /* thanks to H. Morrow Long (ittvax!long) for the next fix */
X if (Lastchar != '\n') /* incomplete last line */
X putchar ('\n'); /* Delim MUST begin new line! */
X puts (Delim);
X if (Count == true && Lastchar != '\n')
X printf ("%s: a missing newline was added to \"'%s'\"\n", ECHO, input);
X if (Count == true && Ctrlcount)
X printf ("%s: %d control character%s may be missing from \"'%s'\"\n",
X ECHO, Ctrlcount, Ctrlcount > 1 ? "s" : "", input);
X (void) fclose (ioptr);
X return (0);
X }
X else
X {
X fprintf (stderr, "shar: Can't open '%s'\n", input);
X return (1);
X }
X }
X
X/*
X Copyout copies its ioptr almost as fast as possible
X except that it has to keep track of the last character
X printed. If the last character is not a newline, then
X shar has to add one so that the end of file delimiter
X is recognized by the shell. This checking costs about
X a 10% difference in user time. Otherwise, it is about
X as fast as cat. It also might count control characters.
X*/
X#define badctrl(c) (iscntrl (c) && !isspace (c))
Xcopyout (ioptr)
Xregister FILE *ioptr;
X {
X register int C;
X register int L;
X register count;
X count = Count;
X while ((C = getc (ioptr)) != EOF)
X {
X if (count == true && badctrl (C)) Ctrlcount++;
X L = putchar (C);
X }
X Lastchar = L;
X }
X
Xoutline (s)
Xregister char *s;
X {
X if (*s)
X {
X while (*s)
X {
X if (Count == true && badctrl (*s)) Ctrlcount++;
X putchar (*s++);
X }
X Lastchar = *(s-1);
X }
X }
X
X#define FSIZE statbuf.st_size
Xshar (file, type, pos)
Xchar *file; /* file or directory to be processed */
Xint type; /* either 'f' for file or 'd' for directory */
Xint pos; /* 0 going in to a file or dir, 1 going out */
X {
X struct stat statbuf;
X char *basefile = file;
X if (!strcmp (file, ".")) return;
X if (stat (file, &statbuf)) FSIZE = 0;
X if (Basename == true)
X {
X while (*basefile) basefile++; /* go to end of name */
X while (basefile > file && *(basefile-1) != '/') basefile--;
X }
X if (pos == 0) /* before the file starts */
X {
X if (type == 'd')
X {
X printf ("if %s ! -d '%s'\n", TEST, basefile);
X printf ("then\n");
X if (Verbose == true)
X printf (" %s: creating directory \"'%s'\"\n", ECHO, basefile);
X printf (" %s '%s'\n", MKDIR, basefile);
X printf ("fi\n");
X if (Verbose == true)
X printf ("%s: entering directory \"'%s'\"\n", ECHO, basefile);
X printf ("%s '%s'\n", CHDIR, basefile);
X }
X else /* type == 'f' */
X {
X if (Verbose == true)
X printf ("%s: extracting \"'%s'\" '(%d character%s)'\n",
X ECHO, basefile, FSIZE, FSIZE > 1 ? "s" : "");
X if (Silent == false) /* this solution by G|ran Uddeborg */
X {
X printf ("if %s -f '%s'\n", TEST, basefile);
X puts ("then");
X printf (" %s: will not over-write existing file \"'%s'\"\n",
X ECHO, basefile);
X puts ("else");
X }
X if (archive (file, basefile)) exit (-1);
X }
X }
X else /* pos == 1, after the file is archived */
X {
X if (type == 'd')
X {
X if (Verbose == true)
X printf ("%s: done with directory \"'%s'\"\n", ECHO, basefile);
X printf ("%s ..\n", CHDIR);
X }
X else /* type == 'f' (plain file) */
X {
X if (Count == true)
X {
X printf ("if %s %d -ne \"`%s '%s'`\"\n",
X TEST, FSIZE, WC_C, basefile);
X puts ("then");
X printf (" %s: error transmitting \"'%s'\" ", ECHO, basefile);
X printf ("'(should have been %d character%s)'\n",
X FSIZE, FSIZE > 1 ? "s" : "");
X puts ("fi");
X }
X if (access (file, 1) == 0) /* executable -> chmod +x */
X printf ("%s '%s'\n", CHMOD, basefile);
X if (Silent == false)
X {
X puts ("fi # end of overwriting check");
X }
X }
X }
X }
SHAR_EOF
fi
if test -f 'traverse.3'
then
echo shar: "will not over-write existing file 'traverse.3'"
else
sed 's/^X//' << \SHAR_EOF > 'traverse.3'
X.TH TRAVERSE 3WI "December 16, 1984"
X.SH NAME
Xtraverse \- recursively traverse a directory
X.SH SYNOPSIS
X.nf
Xtraverse (path, func)
Xchar *path;
Xint (*func) ();
X
Xfunc (path, filetype, position)
Xchar *path;
X.fi
X.SH DESCRIPTION
Xtraverse
Xapplies its argument function func to its argument file pathname path.
XIf path is a directory,
Xthen traverse applies func to all its entries.
XThis traversal is in depth first order
Xso that files are processed in the order
Xthat they are stored in the directory.
X.PP
XThe argument func should take three parameters:
Xa file name,
Xa file type,
Xand a position.
XThe call looks like this for directories:
X.ce
X(*func) (path, 'd', position);
Xand like this for other files:
X.ce
X(*func) (path, 'f', position);
XThe position
Xis 0 when path is first encountered
Xand 1 when traverse is done.
XThis is used to allow processing before and after
Xa directory is processed.
X.SH EXAMPLE
X.nf
Xlist (name, type, pos)
Xchar *name;
X {
X if (type == 'd')
X printf ("%s %s\en", pos ? "Leaving" : "Entering", name);
X else /* type == 'f' */
X printf (" %s\en", name);
X }
X.fi
X.SH AUTHOR
XGary Perlman
X.SH BUGS
XThere are no diagnostics when directories cannot be searched.
SHAR_EOF
fi
if test -f 'traverse.c'
then
echo shar: "will not over-write existing file 'traverse.c'"
else
sed 's/^X//' << \SHAR_EOF > 'traverse.c'
X/*LINTLIBRARY*/
X#include <stdio.h>
X#include <sys/types.h>
X#include <sys/dir.h>
X
X#ifdef MAXNAMLEN
X
X#define namedir(entry) (entry->d_name)
X#define MAXNAME 256
X
X#else
X
X#define DIR FILE
X#define MAXNAME (DIRSIZ+2)
X#define opendir(path) fopen (path, "r")
X#define closedir(dirp) fclose (dirp)
Xstruct direct *
Xreaddir (dirp)
XDIR *dirp;
X {
X static struct direct entry;
X if (dirp == NULL) return (NULL);
X for (;;)
X {
X if (fread (&entry, sizeof (struct direct), 1, dirp) == 0) return (NULL);
X if (entry.d_ino) return (&entry);
X }
X }
Xchar *strncpy ();
Xchar *
Xnamedir (entry)
Xstruct direct *entry;
X {
X static char name[MAXNAME];
X return (strncpy (name, entry->d_name, DIRSIZ));
X }
X
X#endif
X
X#include <sys/stat.h>
X#define isdir(path) (stat(path, &buf) ? 0 : (buf.st_mode&S_IFMT)==S_IFDIR)
X
Xtraverse (path, func)
Xchar *path;
Xint (*func) ();
X {
X DIR *dirp;
X struct direct *entry;
X struct stat buf;
X int filetype = isdir (path) ? 'd' : 'f';
X (*func) (path, filetype, 0);
X if (filetype == 'd')
X {
X if (chdir (path) == 0)
X {
X if (dirp = opendir ("."))
X {
X while (entry = readdir (dirp))
X {
X char name[MAXNAME];
X (void) strcpy (name, namedir (entry));
X if (strcmp(name, ".") && strcmp(name, ".."))
X traverse (name, func);
X }
X (void) closedir(dirp);
X }
X (void) chdir ("..");
X }
X }
X (*func) (path, filetype, 1);
X }
X
X#ifdef STANDALONE
X
Xstatic Indent = 0;
Xtryverse (file, type, pos)
Xchar *file;
X {
X int in;
X if (pos == 0)
X {
X for (in = 0; in < Indent; in++) putchar ('\t');
X if (type == 'd')
X {
X printf ("%s/\n", file);
X Indent++;
X }
X else puts (file);
X }
X else if (type == 'd') Indent--;
X }
X
Xmain (argc, argv) char **argv;
X {
X int tryverse ();
X char *root = argc > 1 ? argv[1] : ".";
X traverse (root, tryverse);
X }
X#endif
SHAR_EOF
fi
exit 0
# End of shell archive
More information about the Alt.sources
mailing list