This commit was manufactured by cvs2svn to create tag 'beta_970304'.

This commit is contained in:
cvs2git 1997-03-11 08:08:07 +00:00
parent e5b9329e55
commit a31db3db4a
110 changed files with 0 additions and 15207 deletions

View File

@ -1,23 +0,0 @@
# Makefile for rmdir(1) and rmdir(3) v1.0
#
# Devin Reade, <gdr@myrias.ab.ca> November 1994.
#
# Define:
# SHELL_COMD if you want to compile the shell command version.
# In this case, do a 'make rmdir'. If you want just
# the rmdir(3) library routine, don't define
# SHELL_COMD and do a 'make rmdir.o'
#
# CHECK_STACK if you want to determine stack usage. If you select
# This option, you must also specify the stack library,
# nominally -l/usr/lib/stack.
CFLAGS = -w -O -DSHELL_COMD -v -s768
LDFLAGS = -v
all: rmdir
install:
cp -f rmdir /bin
cp -f rmdir.1 /usr/man/man1
cp -f rmdir.2 /usr/man/man2

View File

@ -1,31 +0,0 @@
.TH RMDIR 1 "Commands and Applications" "28 November 1994" "Version 1.0"
.SH NAME
rmdir \- remove (delete) a directory
.SH SYNOPSIS
.BR rmdir
[
.IR dir " ..."
]
.SH DESCRIPTION
.BR rmdir
will delete all the listed directories.
.BR rmdir
will print an error and skip the file if
.I dir
is not a directory, is non-empty, or if the user does not
have permission to delete it.
.LP
This program contains material from the ORCA/C run\-time libraries,
Copyright 1987\-1994 Byte Works Inc. Used with permission.
.SH "EXIT STATUS"
.BR rmdir
will have an exit status of zero on success, -1 on failure.
.SH BUGS
It is possible to delete the current directory of
.B rmdir
or another process.
.SH AUTHOR
Devin Reade, <gdr@myrias.ab.ca>
.SH "SEE ALSO"
.BR cp (1),
.BR rm (1).

View File

@ -1,32 +0,0 @@
.TH RMDIR 2 "System Calls" "28 November 1994" "Version 1.0"
.SH NAME
rmdir \- remove (delete) a directory
.SH SYNOPSIS
int \fBrmdir\fR (const char *\fIpath\fR);
.SH DESCRIPTION
.BR rmdir
will remove the directory named by
.I path
if the directory is empty, if it is not a mount point, and if the calling
process has write permission in the parent directory. The directory is
considered empty when it contains only
.B .
and
.B ..
entries.
.SH "RETURN VALUE"
0 if successful, -1 and sets
.B errno
otherwise.
.SH BUGS
Since
.BR rmdir
is not yet implemented as a system call but as a library call, it is
possible to delete a directory which is being used by a process, including
that of
.BR rmdir .
.SH AUTHOR
Devin Reade, <gdr@myrias.ab.ca>
.SH "SEE ALSO"
.BR mkdir (2),
.BR unlink (2).

View File

@ -1,8 +0,0 @@
Name: rmdir
Version: 1.0 (28 Nov 94)
Author: Devin Reade.
Contact: <gdr@myrias.ab.ca>
Where: /bin
FTP: cco.caltech.edu, grind.isca.uiowa.edu
Remove empty directories.

View File

@ -1,99 +0,0 @@
/*
* rmdir - remove directory
*
* A quick and dirty utility for Gno. This will delete all empty
* directories given as arguments. It will skip non-directory files
* directories that aren't empty.
*
* If you don't compile with #define SHELL_COMD, then you just get the
* rmdir(2) system call.
*
* Version 1.0 by Devin Reade <gdr@myrias.ab.ca>
*/
#include <gsos.h>
#include <orca.h>
#include <stdio.h>
#include <stdlib.h>
#include <errno.h>
#define DIRECTORY 0x0F
extern GSString255Ptr __C2GSMALLOC(char *);
extern int _mapErr(int);
extern char *strerror(int errnum);
extern void begin_stack_check(void);
extern int end_stack_check(void);
typedef struct DestroyRecGS {
Word pCount;
GSString255Ptr pathname;
} DestroyRecGS, *DestroyRecPtrGS;
int rmdir (const char *path) {
DestroyRecGS drec;
FileInfoRecGS frec;
int result;
/* make a GSString copy of path */
frec.pCount=3;
if ((frec.pathname = __C2GSMALLOC(path)) == NULL) {
errno = ENOMEM;
return -1;
}
/* check to ensure that it's a directory */
GetFileInfoGS(&frec);
if ((result = toolerror())!=0) {
errno = _mapErr(result);
free(frec.pathname);
return -1;
}
if (frec.fileType != DIRECTORY) {
errno = ENOTDIR;
free(frec.pathname);
return -1;
}
/* it's a directory; try to delete it */
drec.pCount=1;
drec.pathname = frec.pathname;
DestroyGS(&drec);
if ((result = toolerror())!=0) {
errno = _mapErr(result);
free(frec.pathname);
return -1;
}
/* it's been deleted. Clean up and return */
free(frec.pathname);
return 0;
}
#ifdef SHELL_COMD
int main(int argc, char **argv) {
int i, result;
#ifdef CHECK_STACK
begin_stack_check();
#endif
result = 0;
for (i=1; i<argc; i++) { /* loop over all filenames */
if (rmdir(argv[i])!=0) {
fprintf(stderr,"%s: %s: %s. File skipped.\n",argv[0],argv[i],
strerror(errno));
result = 1;
}
}
#ifdef CHECK_STACK
fprintf(stderr,"stack usage: %d bytes\n",end_stack_check());
#endif
return result;
}
#endif /* SHELL_COMD */

View File

@ -1,30 +0,0 @@
tee v1.2 for Gno
The tee that ships with Gno (and hereforth designated v1.0) seems to have
fully buffered output, making it next to useless. This version of tee
has no buffering on stdin/stdout by default, so you see the output as
it's being read. This version also allows multiple output files, appending,
and ignoring of SIGINT.
To install copy tee to /bin and tee.1 to /usr/man/man1, or just type
"dmake install".
This program contains material from the Orca/C Run-Time Libraries,
copyright 1987-1994 by Byte Works, Inc. Used with Permission.
Devin Reade
<gdr@myrias.ab.ca>
$Id: README,v 1.3 1996/09/09 06:12:14 gdr Exp $
Change Log
==========
v1.0 Designated as the version shipped with GNO v2.0.4
v1.1 Rewrite from scratch by Devin Reade. Default changed from
full buffering to no buffering. Added options for multiple
output files, appending and ignoring of SIGINT.
v1.2 Added -b (line buffering) option. STDIN_FILENO is no longer
directly read; stdio is used.

View File

@ -1,34 +0,0 @@
#
# This makefile is intended for use with dmake(1)
#
# $Id: makefile.mk,v 1.3 1996/09/09 06:12:15 gdr Exp $
#
INSTALL = /usr/bin/install
BINDIR = /bin
MANDIR = /man/man1
DEFINES = -D_POSIX_SOURCE
# CFLAGS = -w -i -G25 -v -DCHECK_STACK=1 $(DEFINES)
# LDFLAGS = -l/usr/lib/gnulib -l/usr/lib/stack
CFLAGS = -w -i -O -s768 $(DEFINES)
LDFLAGS = -l/usr/lib/gnulib -s768
tee: tee.o tee.r
@purge
$(CC) $(LDFLAGS) tee.o $(LDLIBS) -o $@
copyfork tee.r tee -r
testtee: testtee.c
@purge
$(CC) -v -w $< -o $@
install:
$(INSTALL) -m755 -obin -gsys -d $(BINDIR) $(MANDIR)
$(INSTALL) -m755 -obin -gsys tee $(BINDIR)
$(INSTALL) -m644 -obin -gsys tee.1 $(MANDIR)
clean clobber:
$(RM) -f tee.r tee.o tee.root testtee testtee.o testtee.root

View File

@ -1,61 +0,0 @@
.\" $Id: tee.1,v 1.3 1996/09/09 06:12:15 gdr Exp $
.\"
.\" .TH TEE 1 "8 September 1996" "Version 1.2" "Commands and Applications"
.TH TEE 1 "Commands and Applications" "8 September 1996" "Version 1.2"
.SH NAME
tee \- Pipe fitting.
.SH SYNOPSIS
.B tee
[
.I -aviV
]
.I file1
[
.IR file2 ...
]
.SH DESCRIPTION
The
.B tee
utility copies standard input to standard
output, making a copy in
.IR file1 ,
.IR file2 ,
etc.
The standard output is by default unbuffered, while output to the
.IR file s
is fully buffered
.LP
The following options are available:
.RS
.IP "\fI-a\fR
Append the output to the
.IR file s
rather than overwriting them.
.IP \fI-b\fR
Use line buffering on stdin and stdout. By default, there is no buffering
on these two streams.
.IP \fI-i\fR
Ignore the SIGINT signal.
.IP \fI-V\fR
Show version and usage information, then exit.
.RE
.LP
The
.B tee
utility takes the default action for all
signals, except in the event of the
.I -i
option.
.LP
If an error occurs while reading stdin, only the first specified
.I file
will contain the output up to that point.
.LP
The return value is 0 on success, and 1 if an error
occurs.
.SH STANDARDS
.B Tee
is POSIX p1003.2 compatible.
.SH HISTORY
.B Tee
first appeared in Gno v1.x. Version 1.1 and later written by Devin Reade.

View File

@ -1,10 +0,0 @@
Name: tee
Version: 1.2 (8 Sep 96)
Author: Devin Reade
Contact: <gdr@myrias.ab.ca>
Where: /bin/tee
FTP: cco.caltech.edu, grind.isca.uiowa.edu.
Tee copies stdin to stdout, by default without buffering. It also makes
a copy of the data to a specified file(s). It is useful when you want to
watch the output of a process, but also save it.

View File

@ -1,175 +0,0 @@
/*
* tee - send a copy of stdin to a file as well as stdout.
*
* Version 1.1 and later by Devin Reade <gdr@myrias.ab.ca>
*
* tee originally appeared with Gno v1.x, but was fully buffered.
* This is a complete re-write which by default uses full buffering
* for the output file, but _no_ buffering on stdin and stdout.
* This buffering behavior can be changed slightly by the -b flag.
*
* $Id: tee.c,v 1.3 1996/09/09 06:12:16 gdr Exp $
*/
#include <sys/types.h>
#include <stdio.h>
#include <stdlib.h>
#include <signal.h>
#include <fcntl.h>
#include <unistd.h>
#include "getopt.h"
#ifdef CHECK_STACK
void begin_stack_check(void);
int end_stack_check(void);
#define STACKSTART begin_stack_check()
#define STACKEND(n) { \
fprintf(stderr,"stack usage: %d bytes\n",end_stack_check()); \
return n; \
}
#else
#define STACKSTART
#define STACKEND(n) return n
#endif
#define BUFFERSIZE 512
#define USAGE { \
fprintf(stderr,"%s %s\nUsage:\t%s %s\n",argv[0],versionstr,argv[0], \
usagestr); \
STACKEND(-1); \
}
char *versionstr = "version 1.2 by Devin Reade";
char *usagestr = "[ -abiV ] filename\n\
\t-a\tappend to filename\n\
\t-i\tignore SIGINT\n";
char buf2[BUFFERSIZE];
int
main(int argc, char **argv)
{
int c, b_flag;
char *mode;
FILE *fp, *fp2;
int characters;
extern int optind;
/*
* initialization
*/
STACKSTART;
mode = "w+";
b_flag = 0;
/*
* parse the command line
*/
while ((c = getopt(argc, argv, "abiV")) != EOF) {
switch (c) {
case 'a':
/* append to instead of truncate output file */
mode = "a+";
break;
case 'b':
/* do line buffering */
b_flag++;
break;
case 'i':
/* ignore SIGINT */
signal(SIGINT, SIG_IGN);
break;
case 'V':
/* FALLTHROUGH */
default:
USAGE;
/* NOTREACHED */
}
}
if ((argc - optind) < 1) {
USAGE;
}
/*
* open the output file
*/
if ((fp = fopen(argv[optind], mode)) == NULL) {
perror("opening master file");
STACKEND(1);
}
/*
* loop until done with the first file
*/
if (b_flag) {
/* line buffering */
setvbuf(stdin, NULL, _IOLBF, 1024);
setvbuf(stdout, NULL, _IOLBF, 1024);
characters = BUFFERSIZE;
} else {
/* no buffering */
setvbuf(stdin, NULL, _IONBF, 0);
setvbuf(stdout, NULL, _IONBF, 0);
characters = 2; /* a value of 2 gives one character reads */
}
/* poll until EOF seen on input or an error occurs */
while (fgets(buf2, characters, stdin) != NULL &&
fputs(buf2, stdout) != EOF &&
fputs(buf2, fp) != EOF);
fflush(fp);
fflush(stdout);
/*
* make additional copies if necessary
*/
optind++;
if (argc <= optind) {
fclose(fp);
STACKEND(0);
}
while (argc > optind) {
size_t count;
/* rewind the master file */
rewind(fp);
/* open the new file */
if ((fp2 = fopen(argv[optind], mode)) == NULL) {
perror("opening duplicate file");
fclose(fp);
STACKEND(1);
}
/* make the copy */
while (!feof(fp) && !(ferror(fp))) {
count = fread(buf2, sizeof(char), BUFFERSIZE, fp);
if (count > 0) {
fwrite(buf2, sizeof(char), count, fp2);
if (ferror(fp2)) {
perror("writing duplicate file");
fclose(fp);
fclose(fp2);
STACKEND(1);
}
}
}
fclose(fp2);
if (ferror(fp)) {
perror("reading master file");
fclose(fp);
STACKEND(1);
}
optind++;
}
fclose(fp);
STACKEND(0);
}

View File

@ -1,18 +0,0 @@
/*
* $Id: tee.rez,v 1.1 1996/09/03 03:56:08 gdr Exp $
*/
#include "Types.Rez"
resource rVersion (0x1, purgeable3, nocrossbank) {
{ 1, 2, 0, /* version 1.2.0 */
release, /* development|alpha|beta|final|release */
0 /* non-final release number */
},
verBritain, /* close enough */
"tee",
"pipe fitting\n"
"Devin Reade <gdr@myrias.com>\n"
"Canada"
};

View File

@ -1,31 +0,0 @@
/*
* This is a test for tee(1) buffering. It prints out LINES lines
* of DIGITS digits each, sleeping for SLEEP seconds between digits.
*
* Usage: ./testtee | ./tee [-b]
*
* $Id: testtee.c,v 1.1 1996/09/09 06:12:16 gdr Exp $
*/
#include <stdio.h>
#include <unistd.h>
#define LINES 3 /* number of lines to print */
#define DIGITS 4 /* digits per line */
#define SLEEP 1 /* seconds to sleep between digits */
int
main(int argc, char **argv)
{
int i, j;
setvbuf(stdout, NULL, _IONBF, 0);
for (i=0; i<LINES; i++) {
for (j=0; j<DIGITS; j++) {
printf(" %d", j);
sleep(SLEEP);
}
printf("\n");
}
return 0;
}

View File

@ -1,26 +0,0 @@
This is test(1) for GNO/ME. For those of you familiar with it
from other platforms, it is a minimal BSD version, not a code-bloated
GNU version. For those not familiar with it, read the man page.
I admit that this has limited functionality with gsh, but it will
become more useful when sh(1) comes out ...
For installation, either type 'dmake install', or copy the files
test to /bin
test.1 to /man/man1
For copying info, see the legalese at the beginning of the file
test.c, or the man page (you have to view the file directly rather
than than via nroff(1) to see it).
Also, regarding the GNO binary:
This program contains material from the ORCA/C Run-Time
Libraries, copyright 1987-1996 by Byte Works, Inc. Used
with permission.
If you have problems with this, let me know. It was a two-hour port.
Devin Reade
February, 1996
<gdr@myrias.com>

View File

@ -1,147 +0,0 @@
# @(#)TEST.csh 5.1 (Berkeley) 6/8/92
alias t './test \!*; echo $status'
#alias t 'test \!*; echo $status'
echo 't -b /dev/ttyp2'
t -b /dev/ttyp2
echo 't -b /dev/jb1a'
t -b /dev/jb1a
echo 't -c test.c'
t -c test.c
echo 't -c /dev/tty'
t -c /dev/tty
echo 't -d test.c'
t -d test.c
echo 't -d /etc'
t -d /etc
echo 't -e noexist'
t -e noexist
echo 't -e test.c'
t -e test.c
echo 't -f noexist'
t -f noexist
echo 't -f /dev/tty'
t -f /dev/tty
echo 't -f test.c'
t -f test.c
echo 't -g test.c'
t -g test.c
echo 't -g /bin/ps'
t -g /bin/ps
echo 't -n ""'
t -n ""
echo 't -n "hello"'
t -n "hello"
echo 't -p test.c'
t -p test.c
echo 't -r noexist'
t -r noexist
echo 't -r /etc/master.passwd'
t -r /etc/master.passwd
echo 't -r test.c'
t -r test.c
echo 't -s noexist'
t -s noexist
echo 't -s /dev/null'
t -s /dev/null
echo 't -s test.c'
t -s test.c
echo 't -t 20'
t -t 20
echo 't -t 0'
t -t 0
echo 't -u test.c'
t -u test.c
echo 't -u /bin/rcp'
t -u /bin/rcp
echo 't -w noexist'
t -w noexist
echo 't -w /etc/master.passwd'
t -w /etc/master.passwd
echo 't -w /dev/null'
t -w /dev/null
echo 't -x noexist'
t -x noexist
echo 't -x /bin/ps'
t -x /bin/ps
echo 't -x /etc/motd'
t -x /etc/motd
echo 't -z ""'
t -z ""
echo 't -z "foo"'
t -z "foo"
echo 't "foo"'
t "foo"
echo 't ""'
t ""
echo 't "hello" = "hello"'
t "hello" = "hello"
echo 't "hello" = "goodbye"'
t "hello" = "goodbye"
echo 't "hello" != "hello"'
t "hello" != "hello"
echo 't "hello" != "goodbye"'
t "hello" != "goodbye"
echo 't 200 -eq 200'
t 200 -eq 200
echo 't 34 -eq 222'
t 34 -eq 222
echo 't 200 -ne 200'
t 200 -ne 200
echo 't 34 -ne 222'
t 34 -ne 222
echo 't 200 -gt 200'
t 200 -gt 200
echo 't 340 -gt 222'
t 340 -gt 222
echo 't 200 -ge 200'
t 200 -ge 200
echo 't 34 -ge 222'
t 34 -ge 222
echo 't 200 -lt 200'
t 200 -lt 200
echo 't 34 -lt 222'
t 34 -lt 222
echo 't 200 -le 200'
t 200 -le 200
echo 't 340 -le 222'
t 340 -le 222
echo 't 700 -le 1000 -a -n "1" -a "20" = "20"'
t 700 -le 1000 -a -n "1" -a "20" = "20"
echo 't ! \( 700 -le 1000 -a -n "1" -a "20" = "20" \)'
t ! \( 700 -le 1000 -a -n "1" -a "20" = "20" \)
echo 't foo -a ""'
t foo -a ""
echo 't "" -a foo'
t "" -a foo
echo 't "" -a ""'
t "" -a ""
echo 't "" -o ""'
t "" -o ""

View File

@ -1,56 +0,0 @@
# Copyright (c) 1988 The Regents of the University of California.
# All rights reserved.
#
# This code is derived from software contributed to Berkeley by
# Kenneth Almquist.
#
# Redistribution and use in source and binary forms, with or without
# modification, are permitted provided that the following conditions
# are met:
# 1. Redistributions of source code must retain the above copyright
# notice, this list of conditions and the following disclaimer.
# 2. Redistributions in binary form must reproduce the above copyright
# notice, this list of conditions and the following disclaimer in the
# documentation and/or other materials provided with the distribution.
# 3. All advertising materials mentioning features or use of this software
# must display the following acknowledgement:
# This product includes software developed by the University of
# California, Berkeley and its contributors.
# 4. Neither the name of the University nor the names of its contributors
# may be used to endorse or promote products derived from this software
# without specific prior written permission.
#
# THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
# ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
# ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
# FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
# DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
# OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
# HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
# LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
# OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
# SUCH DAMAGE.
#
# @(#)binary_op 1.2 (Berkeley) 6/3/92
#
#
# List of binary operators used by test
#
OR1 -o 1
OR2 | 1
AND1 -a 2
AND2 & 2
STREQ = 4 OP_STRING
STRNE != 4 OP_STRING
EQ -eq 4 OP_INT
NE -ne 4 OP_INT
GT -gt 4 OP_INT
LT -lt 4 OP_INT
LE -le 4 OP_INT
GE -ge 4 OP_INT

View File

@ -1,58 +0,0 @@
#
# This file is intended for use with dmake
#
# $Id: makefile.mk,v 1.2 1996/02/11 00:59:16 gdr Exp $
#
# VAFLAGS must use an optimization level of at least -O8, and no
# -g or -G* flag
#
# Include -DCHECK_STACK in DEFINES to get stack usage and debug info.
# If you use -DCHECK_STACK, you will also have to add the stack checking
# library. I keep mine in "/usr/lib/stack".
#
DEFINES = -Dlint -DGNO
STACK = -s1280
CFLAGS += $(DEFINES) $(STACK) -w -O
VAFLAGS += $(DEFINES) $(STACK) -w -O
LDFLAGS += -v
LDLIBS =
OBJS = test.o test2.o operators.o
ROOTS = test.root test2.root operators.root
BINDIR = /bin
MANDIR = /man
test: $(OBJS) test.r
@purge
$(CC) $(LDFLAGS) $(OBJS) $(LDLIBS) -o $@
copyfork test.r test -r
test.o: test.c operators.h
@purge
$(CC) -c $(CFLAGS) -o $@ test.c
test2.o: test2.c
@purge
$(CC) -c $(VAFLAGS) -o $@ test2.c
operators.o: operators.c operators.h
@purge
$(CC) -c $(CFLAGS) -o $@ operators.c
operators.c operators.h: unaryop binaryop
$(MAKE) make_op
clean:
$(RM) -f $(OBJS) $(ROOTS) test.r
clobber: clean
$(RM) -f test
install:
cp test $(BINDIR)
cp test.1 $(MANDIR)/man1
# use this rule to if you update binary_ops, or unary_ops
make_op:
@echo "$(MAKE) make_op invoked"
# sh ${.CURDIR}/mkops

View File

@ -1,84 +0,0 @@
# Copyright (c) 1988 The Regents of the University of California.
# All rights reserved.
#
# This code is derived from software contributed to Berkeley by
# Kenneth Almquist.
#
# Redistribution and use in source and binary forms, with or without
# modification, are permitted provided that the following conditions
# are met:
# 1. Redistributions of source code must retain the above copyright
# notice, this list of conditions and the following disclaimer.
# 2. Redistributions in binary form must reproduce the above copyright
# notice, this list of conditions and the following disclaimer in the
# documentation and/or other materials provided with the distribution.
# 3. All advertising materials mentioning features or use of this software
# must display the following acknowledgement:
# This product includes software developed by the University of
# California, Berkeley and its contributors.
# 4. Neither the name of the University nor the names of its contributors
# may be used to endorse or promote products derived from this software
# without specific prior written permission.
#
# THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
# ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
# ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
# FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
# DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
# OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
# HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
# LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
# OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
# SUCH DAMAGE.
#
# @(#)mkops 1.3 (Berkeley) 6/3/92
#
#exec > operators.h
(
awk '/^[^#]/ {printf "#define %s %d\n", $1, n++}' unary_op binary_op
awk '/^[^#]/ {n++}
END {printf "\n#define FIRST_BINARY_OP %d\n", n}
' unary_op
echo '
#define OP_INT 1 /* arguments to operator are integer */
#define OP_STRING 2 /* arguments to operator are string */
#define OP_FILE 3 /* argument is a file name */
extern char *const unary_op[];
extern char *const binary_op[];
extern const char op_priority[];
extern const char op_argflag[];'
) >operators.h
#exec > operators.c
(
echo '/*
* Operators used in the test command.
*/
#include <stdio.h>
#include "operators.h"
char *const unary_op[] = {'
awk '/^[^#]/ {printf " \"%s\",\n", $2}' unary_op
echo ' NULL
};
char *const binary_op[] = {'
awk '/^[^#]/ {printf " \"%s\",\n", $2}' binary_op
echo ' NULL
};
const char op_priority[] = {'
awk '/^[^#]/ {printf " %s,\n", $3}' unary_op binary_op
echo '};
const char op_argflag[] = {'
awk '/^[^#]/ {if (length($4) > 0) printf " %s,\n", $4
else printf " 0,\n"}
' unary_op binary_op
echo '};'
) >operators.c

View File

@ -1,117 +0,0 @@
/*
* Operators used in the test command.
*
* $Id: operators.c,v 1.2 1996/02/11 05:47:04 gdr Exp $
*/
#include <stdio.h>
#include "operators.h"
char *const unary_op[] = {
"!",
"-b",
"-c",
"-d",
"-e",
"-f",
"-g",
"-k",
"-n",
"-p",
"-r",
"-s",
"-t",
"-u",
"-w",
"-x",
"-z",
NULL
};
char *const binary_op[] = {
"-o",
"|",
"-a",
"&",
"=",
"!=",
"-eq",
"-ne",
"-gt",
"-lt",
"-le",
"-ge",
NULL
};
char *const andor_op[] = {
"-o",
"|",
"-a",
"&",
NULL
};
const char op_priority[] = {
3,
12,
12,
12,
12,
12,
12,
12,
12,
12,
12,
12,
12,
12,
12,
12,
12,
1,
1,
2,
2,
4,
4,
4,
4,
4,
4,
4,
4,
};
const char op_argflag[] = {
0,
OP_FILE,
OP_FILE,
OP_FILE,
OP_FILE,
OP_FILE,
OP_FILE,
OP_FILE,
OP_STRING,
OP_FILE,
OP_FILE,
OP_FILE,
OP_INT,
OP_FILE,
OP_FILE,
OP_FILE,
OP_STRING,
0,
0,
0,
0,
OP_STRING,
OP_STRING,
OP_INT,
OP_INT,
OP_INT,
OP_INT,
OP_INT,
OP_INT,
};

View File

@ -1,56 +0,0 @@
/*
* $Id: operators.h,v 1.1 1996/02/10 08:27:31 gdr Exp $
*/
#ifndef __P
#ifdef __STDC__
#define __P(a) a
#else
#define __P(a) ()
#endif
#endif
#define NOT 0
#define ISBLOCK 1
#define ISCHAR 2
#define ISDIR 3
#define ISEXIST 4
#define ISFILE 5
#define ISSETGID 6
#define ISSTICKY 7
#define STRLEN 8
#define ISFIFO 9
#define ISREAD 10
#define ISSIZE 11
#define ISTTY 12
#define ISSETUID 13
#define ISWRITE 14
#define ISEXEC 15
#define NULSTR 16
#define OR1 17
#define OR2 18
#define AND1 19
#define AND2 20
#define STREQ 21
#define STRNE 22
#define EQ 23
#define NE 24
#define GT 25
#define LT 26
#define LE 27
#define GE 28
#define FIRST_BINARY_OP 17
#define OP_INT 1 /* arguments to operator are integer */
#define OP_STRING 2 /* arguments to operator are string */
#define OP_FILE 3 /* argument is a file name */
extern char *const unary_op[];
extern char *const binary_op[];
extern char *const andor_op[];
extern const char op_priority[];
extern const char op_argflag[];
extern void err __P((const char *, ...));

View File

@ -1,275 +0,0 @@
.\" Copyright (c) 1991 Regents of the University of California.
.\" All rights reserved.
.\"
.\" This code is derived from software contributed to Berkeley by
.\" the Institute of Electrical and Electronics Engineers, Inc.
.\"
.\" Redistribution and use in source and binary forms, with or without
.\" modification, are permitted provided that the following conditions
.\" are met:
.\" 1. Redistributions of source code must retain the above copyright
.\" notice, this list of conditions and the following disclaimer.
.\" 2. Redistributions in binary form must reproduce the above copyright
.\" notice, this list of conditions and the following disclaimer in the
.\" documentation and/or other materials provided with the distribution.
.\" 3. All advertising materials mentioning features or use of this software
.\" must display the following acknowledgement:
.\" This product includes software developed by the University of
.\" California, Berkeley and its contributors.
.\" 4. Neither the name of the University nor the names of its contributors
.\" may be used to endorse or promote products derived from this software
.\" without specific prior written permission.
.\"
.\" THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
.\" ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
.\" IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
.\" ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
.\" FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
.\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
.\" OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
.\" HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
.\" LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
.\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
.\" SUCH DAMAGE.
.\"
.\" @(#)test.1 6.6 (Berkeley) 6/8/92
.\"
.\" $Id: test.1,v 1.1 1996/02/10 08:27:32 gdr Exp $
.\"
.TH TEST 1 "Commands and Applications" "9 February 1996" "Version 1.0"
.SH NAME
test \- Condition evaluation utility.
.SH SYNOPSIS
.B test
.I expression
.SH DESCRIPTION
The
.B test
utility evaluates the expression and, if it evaluates
to true, returns a zero (true) exit status; otherwise
it returns 1 (false).
If there is no expression, test also
returns 1 (false).
.LP
All operators and flags are separate arguments to the
.B test
utility.
.LP
The following primaries are used to construct
.IR expression :
.IP "\fB-b\fR \fIfile\fR"
True if
.I file
exists and is a block special
file.
.IP "\fB-c\fR \fIfile\fR"
True if
.I file
exists and is a character
special file.
.IP "\fB-d\fR \fIfile\fR"
True if
.I file
exists and is a directory.
.IP "\fB-e\fR \fIfile\fR"
True if
.I file
exists (regardless of type).
.IP "\fB-f\fR \fIfile\fR"
True if
.I file
exists and is a regular file.
.IP "\fB-g\fR \fIfile\fR"
True if
.I file
exists and its set group ID flag
is set.
.IP "\fB-n\fR \fIstring\fR"
True if the length of
.I string
is nonzero.
.IP "\fB-p\fR \fIfile\fR"
True if
.I file
is a named pipe (FIFO).
.IP "\fB-r\fR \fIfile\fR"
True if
.I file
exists and is readable.
.IP "\fB-s\fR \fIfile\fR"
True if
.I file
exists and has a size greater
than zero.
.IP "\fB-t\fR [ \fIfile_descriptor\fR ]"
True if the file whose file descriptor number
is
.I file_descriptor
(default 1) is open and is
associated with a terminal.
.IP "\fB-u\fR \fIfile\fR"
True if
.I file
exists and its set user ID flag
is set.
.IP "\fB-w\fR \fIfile\fR"
True if
.I file
exists and is writable.
True
indicates only that the write flag is on.
The file is not writable on a read-only file
system even if this test indicates true.
.IP "\fB-x\fR \fIfile\fR"
True if
.I file
exists and is executable.
True
indicates only that the execute flag is on.
If
.I file
is a directory, true indicates that
.I file
can be searched.
.IP "\fB-z\fR \fIstring\fR"
True if the length of
.I string
is zero.
.IP "\fIstring\fR"
True if
.I string
is not the null
string.
.IP "\fIs1\fR \fB=\fR \fIs2\fR"
True if the strings
.I s1
and
.I s2
are identical.
.IP "\fIs1\fR \fB!=\fR \fIs2\fR"
True if the strings
.I s1
and
.I s2
are not identical.
.IP "\fIn1\fR \fB-eq\fR \fIn2\fR"
True if the integers
.I n1
and
.I n2
are algebraically
equal.
.IP "\fIn1\fR \fB-ne\fR \fIn2\fR"
True if the integers
.I n1
and
.I n2
are not
algebraically equal.
.IP "\fIn1\fR \fB-gt\fR \fIn2\fR"
True if the integer
.I n1
is algebraically
greater than the integer
.I n2 .
.IP "\fIn1\fR \fB-ge\fR \fIn2\fR"
True if the integer
.I n1
is algebraically
greater than or equal to the integer
.I n2 .
.IP "\fIn1\fR \fB-lt\fR \fIn2\fR"
True if the integer
.I n1
is algebraically less
than the integer
.I n2 .
.IP "\fIn1\fR \fB-le\fR \fIn2\fR"
True if the integer
.I n1
is algebraically less
than or equal to the integer
.I n2 .
.LP
These primaries can be combined with the following operators:
.IP "\fB!\fR \fIexpression\fR"
True if
.I expression
is false.
.IP "\fIexpression1\fR \fB-a\fR \fIexpression2\fR"
True if both
.I expression1
and
.I expression2
are true.
.IP "\fIexpression1\fR \fB-o\fR \fIexpression2\fR"
True if either
.I expression1
or
.I expression2
are true.
.IP "\fB\&(\fR \fIexpression\fR \fB\&)\fR"
True if
.I expression
is true.
.LP
The
.B -a
operator has higher precedence than the
.B -o
operator.
.SH GRAMMAR AMBIGUITY
The
.B test
grammar is inherently ambiguous. In order to assure a degree of consistency,
the cases described in the
.IR "POSIX 1003.2" ,
section D11.2/4.62.4, standard
are evaluated consistently according to the rules specified in the
standards document. All other cases are subject to the ambiguity in the
command semantics.
.SH GNO CAVEATS
The
.BR \-b ,
.BR \-c ,
.BR \-g ,
and
.BR \-u
operators always cause a false return value (as of GNO v2.0.4)
since block- and character-special files, and the setuid and setgid bits
are not currently available under GS/OS.
.LP
Because of the implementation of
.BR stat (2)
under GNO v2.0.4, the
.BR \-x
operator will return false if
.I file
is a directory.
.SH RETURN VALUES
The
.B test
utility exits with one of the following values:
.IP \fB0\fR
.I expression
evaluated to true.
.IP \fB1\fR
.I expression
evaluated to false or expression was missing.
.IP \fB>1\fR
An error occurred.
.SH AUTHOR
This code is derived from software contributed to Berkeley by
Kenneth Almquist, and is based on BSD
.BR test
version 5.4.
.LP
The GNO port of
.BR test
was done by Devin Reade, <gdr@myrias.com>.
.SH STANDARDS
The
.B test
function is expected to be
.I "POSIX 1003.2"
compatible.

View File

@ -1,582 +0,0 @@
/*
* $Id: test.c,v 1.2 1996/02/11 05:47:04 gdr Exp $
*/
/*-
* Copyright (c) 1992 The Regents of the University of California.
* All rights reserved.
*
* This code is derived from software contributed to Berkeley by
* Kenneth Almquist.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* 3. All advertising materials mentioning features or use of this software
* must display the following acknowledgement:
* This product includes software developed by the University of
* California, Berkeley and its contributors.
* 4. Neither the name of the University nor the names of its contributors
* may be used to endorse or promote products derived from this software
* without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*/
#ifndef lint
char copyright[] =
"@(#) Copyright (c) 1992 The Regents of the University of California.\n\
All rights reserved.\n";
#endif /* not lint */
#ifndef lint
static char sccsid[] = "@(#)test.c 5.4 (Berkeley) 2/12/93";
#endif /* not lint */
#include <sys/types.h>
#include <sys/stat.h>
#include <errno.h>
#include <stdlib.h>
#include <string.h>
#include <stdio.h>
#include <unistd.h>
#include <ctype.h>
#include "operators.h"
#define STACKSIZE 12
#define NESTINCR 16
/* data types */
#define STRING 0
#define INTEGER 1
#define BOOLEAN 2
#define IS_BANG(s) (s[0] == '!' && s[1] == '\0')
#ifdef CHECK_STACK
void begin_stack_check(void);
int end_stack_check(void);
#endif
/*
* This structure hold a value. The type keyword specifies the type of
* the value, and the union u holds the value. The value of a boolean
* is stored in u.num (1 = TRUE, 0 = FALSE).
*/
struct value {
int type;
union {
char *string;
long num;
} u;
};
struct operator {
short op; /* Which operator. */
short pri; /* Priority of operator. */
};
struct filestat {
char *name; /* Name of file. */
int rcode; /* Return code from stat. */
struct stat stat; /* Status info on file. */
};
static int expr_is_false __P((struct value *));
static void expr_operator __P((int, struct value *, struct filestat *));
static long chk_atol __P((char *));
static int lookup_op __P((char *, char *const *));
static void overflow __P((void));
static int posix_binary_op __P((char **));
static int posix_unary_op __P((char **));
static void syntax __P((void));
#ifdef CHECK_STACK
#define RETURN(val) \
{ \
int i; \
i = (val); \
printf("DEBUG: test returning %d\n\n",i); \
printf("stack usage: %d bytes\n",end_stack_check()); \
return i; \
}
#else
#define RETURN(val) return val
#endif
int
main(int argc, char *argv[])
{
struct operator opstack[STACKSIZE];
struct operator *opsp;
struct value valstack[STACKSIZE + 1];
struct value *valsp;
struct filestat fs;
char c, **ap, *opname, *p;
int binary, nest, op, pri, ret_val, skipping;
#ifdef CHECK_STACK
begin_stack_check();
#endif
if ((p = argv[0]) == NULL) {
err("test: argc is zero.\n");
exit(2);
}
if (*p != '\0' && p[strlen(p) - 1] == '[') {
if (strcmp(argv[--argc], "]"))
err("missing ]");
argv[argc] = NULL;
}
ap = argv + 1;
fs.name = NULL;
/*
* Test(1) implements an inherently ambiguous grammer. In order to
* assure some degree of consistency, we special case the POSIX 1003.2
* requirements to assure correct evaluation for POSIX scripts. The
* following special cases comply with POSIX P1003.2/D11.2 Section
* 4.62.4.
*/
switch(argc - 1) {
case 0: /* % test */
RETURN(1);
break;
case 1: /* % test arg */
/* MIPS machine returns NULL of '[ ]' is called. */
RETURN((argv[1] == NULL || *argv[1] == '\0') ? 1 : 0);
break;
case 2: /* % test op arg */
opname = argv[1];
if (IS_BANG(opname)) {
RETURN((*argv[2] == '\0') ? 0 : 1);
} else {
ret_val = posix_unary_op(&argv[1]);
if (ret_val >= 0) {
RETURN(ret_val);
}
}
break;
case 3: /* % test arg1 op arg2 */
if (IS_BANG(argv[1])) {
ret_val = posix_unary_op(&argv[1]);
if (ret_val >= 0) {
RETURN(!ret_val);
}
} else if (lookup_op(argv[2], andor_op) < 0) {
ret_val = posix_binary_op(&argv[1]);
if (ret_val >= 0) {
RETURN(ret_val);
}
}
break;
case 4: /* % test ! arg1 op arg2 */
if (IS_BANG(argv[1]) && lookup_op(argv[3], andor_op) < 0) {
ret_val = posix_binary_op(&argv[2]);
if (ret_val >= 0) {
RETURN(!ret_val);
}
}
break;
default:
break;
}
/*
* We use operator precedence parsing, evaluating the expression as
* we parse it. Parentheses are handled by bumping up the priority
* of operators using the variable "nest." We use the variable
* "skipping" to turn off evaluation temporarily for the short
* circuit boolean operators. (It is important do the short circuit
* evaluation because under NFS a stat operation can take infinitely
* long.)
*/
opsp = opstack + STACKSIZE;
valsp = valstack;
nest = skipping = 0;
if (*ap == NULL) {
valstack[0].type = BOOLEAN;
valstack[0].u.num = 0;
goto done;
}
for (;;) {
opname = *ap++;
if (opname == NULL)
syntax();
if (opname[0] == '(' && opname[1] == '\0') {
nest += NESTINCR;
continue;
} else if (*ap && (op = lookup_op(opname, unary_op)) >= 0) {
if (opsp == &opstack[0])
overflow();
--opsp;
opsp->op = op;
opsp->pri = op_priority[op] + nest;
continue;
} else {
valsp->type = STRING;
valsp->u.string = opname;
valsp++;
}
for (;;) {
opname = *ap++;
if (opname == NULL) {
if (nest != 0)
syntax();
pri = 0;
break;
}
if (opname[0] != ')' || opname[1] != '\0') {
if ((op = lookup_op(opname, binary_op)) < 0)
syntax();
op += FIRST_BINARY_OP;
pri = op_priority[op] + nest;
break;
}
if ((nest -= NESTINCR) < 0)
syntax();
}
while (opsp < &opstack[STACKSIZE] && opsp->pri >= pri) {
binary = opsp->op;
for (;;) {
valsp--;
c = op_argflag[opsp->op];
if (c == OP_INT) {
if (valsp->type == STRING)
valsp->u.num =
chk_atol(valsp->u.string);
valsp->type = INTEGER;
} else if (c >= OP_STRING) {
/* OP_STRING or OP_FILE */
if (valsp->type == INTEGER) {
if ((p = malloc(32)) == NULL)
err("%s",
strerror(errno));
#ifdef SHELL
#error "gdr: is this supposed to be %ld ? "
fmtstr(p, 32, "%d",
valsp->u.num);
#else
(void)sprintf(p,
"%ld", valsp->u.num);
#endif
valsp->u.string = p;
} else if (valsp->type == BOOLEAN) {
if (valsp->u.num)
valsp->u.string =
"true";
else
valsp->u.string = "";
}
valsp->type = STRING;
if (c == OP_FILE && (fs.name == NULL ||
strcmp(fs.name, valsp->u.string))) {
fs.name = valsp->u.string;
fs.rcode =
stat(valsp->u.string,
&fs.stat);
}
}
if (binary < FIRST_BINARY_OP)
break;
binary = 0;
}
if (!skipping)
expr_operator(opsp->op, valsp, &fs);
else if (opsp->op == AND1 || opsp->op == OR1)
skipping--;
valsp++; /* push value */
opsp++; /* pop operator */
}
if (opname == NULL)
break;
if (opsp == &opstack[0])
overflow();
if (op == AND1 || op == AND2) {
op = AND1;
if (skipping || expr_is_false(valsp - 1))
skipping++;
}
if (op == OR1 || op == OR2) {
op = OR1;
if (skipping || !expr_is_false(valsp - 1))
skipping++;
}
opsp--;
opsp->op = op;
opsp->pri = pri;
}
done: { RETURN(expr_is_false(&valstack[0])); }
}
static int
expr_is_false(struct value *val)
{
if (val->type == STRING) {
if (val->u.string[0] == '\0')
return (1);
} else { /* INTEGER or BOOLEAN */
if (val->u.num == 0)
return (1);
}
return (0);
}
/*
* Execute an operator. Op is the operator. Sp is the stack pointer;
* sp[0] refers to the first operand, sp[1] refers to the second operand
* (if any), and the result is placed in sp[0]. The operands are converted
* to the type expected by the operator before expr_operator is called.
* Fs is a pointer to a structure which holds the value of the last call
* to stat, to avoid repeated stat calls on the same file.
*/
static void
expr_operator(int op, struct value *sp, struct filestat *fs)
{
int i;
switch (op) {
case NOT:
sp->u.num = expr_is_false(sp);
sp->type = BOOLEAN;
break;
case ISEXIST:
if (fs == NULL || fs->rcode == -1)
goto false;
else
goto true;
#ifdef GNO
case ISREAD:
i = S_IREAD;
goto filebit; /* true if (stat.st_mode & i) != 0 */
case ISWRITE:
i = S_IWRITE;
goto filebit; /* true if (stat.st_mode & i) != 0 */
case ISEXEC:
i = S_IEXEC;
goto filebit; /* true if (stat.st_mode & i) != 0 */
#else
case ISREAD:
i = S_IROTH;
goto permission;
case ISWRITE:
i = S_IWOTH;
goto permission;
case ISEXEC:
i = S_IXOTH;
permission:
if (fs->stat.st_uid == geteuid())
i <<= 6;
else if (fs->stat.st_gid == getegid())
i <<= 3;
goto filebit; /* true if (stat.st_mode & i) != 0 */
#endif /* not GNO */
case ISFILE:
i = S_IFREG;
goto filetype;
case ISDIR:
i = S_IFDIR;
goto filetype;
case ISCHAR:
i = S_IFCHR;
goto filetype;
case ISBLOCK:
i = S_IFBLK;
goto filetype;
case ISFIFO:
i = S_IFIFO;
goto filetype;
filetype:
if ((fs->stat.st_mode & S_IFMT) == i && fs->rcode >= 0)
true: sp->u.num = 1;
else
false: sp->u.num = 0;
sp->type = BOOLEAN;
break;
case ISSETUID:
i = S_ISUID;
goto filebit;
case ISSETGID:
i = S_ISGID;
goto filebit;
case ISSTICKY:
i = S_ISVTX;
filebit:
if (fs->stat.st_mode & i && fs->rcode >= 0)
goto true;
goto false;
case ISSIZE:
sp->u.num = fs->rcode >= 0 ? fs->stat.st_size : 0L;
sp->type = INTEGER;
break;
case ISTTY:
sp->u.num = isatty(sp->u.num);
sp->type = BOOLEAN;
break;
case NULSTR:
if (sp->u.string[0] == '\0')
goto true;
goto false;
case STRLEN:
sp->u.num = strlen(sp->u.string);
sp->type = INTEGER;
break;
case OR1:
case AND1:
/*
* These operators are mostly handled by the parser. If we
* get here it means that both operands were evaluated, so
* the value is the value of the second operand.
*/
*sp = *(sp + 1);
break;
case STREQ:
case STRNE:
i = 0;
if (!strcmp(sp->u.string, (sp + 1)->u.string))
i++;
if (op == STRNE)
i = 1 - i;
sp->u.num = i;
sp->type = BOOLEAN;
break;
case EQ:
if (sp->u.num == (sp + 1)->u.num)
goto true;
goto false;
case NE:
if (sp->u.num != (sp + 1)->u.num)
goto true;
goto false;
case GT:
if (sp->u.num > (sp + 1)->u.num)
goto true;
goto false;
case LT:
if (sp->u.num < (sp + 1)->u.num)
goto true;
goto false;
case LE:
if (sp->u.num <= (sp + 1)->u.num)
goto true;
goto false;
case GE:
if (sp->u.num >= (sp + 1)->u.num)
goto true;
goto false;
}
}
static int
lookup_op(char *name, char *const *table)
{
register char *const * tp;
register char const *p;
char c;
c = name[1];
for (tp = table; (p = *tp) != NULL; tp++)
if (p[1] == c && !strcmp(p, name))
return (tp - table);
return (-1);
}
static int
posix_unary_op(char **argv)
{
struct filestat fs;
struct value valp;
int op, c;
char *opname;
opname = *argv;
if ((op = lookup_op(opname, unary_op)) < 0)
return (-1);
c = op_argflag[op];
opname = argv[1];
valp.u.string = opname;
if (c == OP_FILE) {
fs.name = opname;
fs.rcode = stat(opname, &fs.stat);
} else if (c != OP_STRING)
return (-1);
expr_operator(op, &valp, &fs);
return (valp.u.num == 0);
}
static int
posix_binary_op(char **argv)
{
struct value v[2];
int op, c;
char *opname;
opname = argv[1];
if ((op = lookup_op(opname, binary_op)) < 0)
return (-1);
op += FIRST_BINARY_OP;
c = op_argflag[op];
if (c == OP_INT) {
v[0].u.num = chk_atol(argv[0]);
v[1].u.num = chk_atol(argv[2]);
} else {
v[0].u.string = argv[0];
v[1].u.string = argv[2];
}
expr_operator(op, v, NULL);
return (v[0].u.num == 0);
}
/*
* Integer type checking.
*/
static long
chk_atol(char *v)
{
char *p;
long r;
errno = 0;
r = strtol(v, &p, 10);
if (errno != 0)
err("\"%s\" -- out of range.", v);
while (isspace(*p))
p++;
if (*p != '\0')
err("illegal operand \"%s\" -- expected integer.", v);
return (r);
}
static void
syntax(void)
{
err("syntax error");
}
static void
overflow(void)
{
err("expression is too complex");
}

View File

@ -1,11 +0,0 @@
Name: test
Version: 1.0 (9 Feb 96)
Shell: GNO/ME
Author: Devin Reade
Contact: gdr@myrias.com
Where: /bin
FTP: grind.isca.uiowa.edu
The test utility evaluates string and integer expressions and, if
it evaluates to true, returns a zero (true) exit status; otherwise it
returns 1 (false). Test is used mainly in shell scripts.

View File

@ -1,18 +0,0 @@
/*
* $Id: test.rez,v 1.1 1996/02/10 08:27:33 gdr Exp $
*/
#include "Types.Rez"
resource rVersion (0x1, purgeable3, nocrossbank) {
{ 1, 0, 0, /* version 1.0.0 */
release, /* development|alpha|beta|final|release */
0 /* non-final release number */
},
verBritain, /* close enough */
"test",
"Condition evaluation utility\n"
"Devin Reade <gdr@myrias.com>\n"
"Canada"
};

View File

@ -1,36 +0,0 @@
/*
* $Id: test2.c,v 1.2 1996/02/11 05:47:05 gdr Exp $
*/
#include <stdio.h>
#include <stdlib.h>
#include "operators.h"
#if __STDC__
#include <stdarg.h>
#else
#include <varargs.h>
#endif
void
#if __STDC__
err(const char *fmt, ...)
#else
err(fmt, va_alist)
char *fmt;
va_dcl
#endif
{
va_list ap;
#if __STDC__
va_start(ap, fmt);
#else
va_start(ap);
#endif
(void)fprintf(stderr, "test: ");
(void)vfprintf(stderr, fmt, ap);
va_end(ap);
(void)fprintf(stderr, "\n");
exit(2);
/* NOTREACHED */
}

View File

@ -1,59 +0,0 @@
# Copyright (c) 1988 The Regents of the University of California.
# All rights reserved.
#
# This code is derived from software contributed to Berkeley by
# Kenneth Almquist.
#
# Redistribution and use in source and binary forms, with or without
# modification, are permitted provided that the following conditions
# are met:
# 1. Redistributions of source code must retain the above copyright
# notice, this list of conditions and the following disclaimer.
# 2. Redistributions in binary form must reproduce the above copyright
# notice, this list of conditions and the following disclaimer in the
# documentation and/or other materials provided with the distribution.
# 3. All advertising materials mentioning features or use of this software
# must display the following acknowledgement:
# This product includes software developed by the University of
# California, Berkeley and its contributors.
# 4. Neither the name of the University nor the names of its contributors
# may be used to endorse or promote products derived from this software
# without specific prior written permission.
#
# THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
# ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
# ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
# FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
# DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
# OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
# HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
# LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
# OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
# SUCH DAMAGE.
#
# @(#)unary_op 1.2 (Berkeley) 6/3/92
#
#
# List of unary operators used by test.
#
NOT ! 3
ISBLOCK -b 12 OP_FILE
ISCHAR -c 12 OP_FILE
ISDIR -d 12 OP_FILE
ISEXIST -e 12 OP_FILE
ISFILE -f 12 OP_FILE
ISSETGID -g 12 OP_FILE
ISSTICKY -k 12 OP_FILE
STRLEN -n 12 OP_STRING
ISFIFO -p 12 OP_FILE
ISREAD -r 12 OP_FILE
ISSIZE -s 12 OP_FILE
ISTTY -t 12 OP_INT
ISSETUID -u 12 OP_FILE
ISWRITE -w 12 OP_FILE
ISEXEC -x 12 OP_FILE
NULSTR -z 12 OP_STRING

View File

@ -1,12 +0,0 @@
CFLAGS = -w -O
LDFLAGS =
renram5: renram5.o renram5.r
$(CC) $(LDFLAGS) renram5.o $(LDLIBS) -o $@
copyfork renram5.r renram5 -r
clean:
$(RM) -f renram5.o renram5.root renram5.r
clobber: clean
$(RM) -f renram5

View File

@ -1,12 +0,0 @@
This is a quick and dirty program intended to rename /RAM5 at
boot time.
See the man page for details.
If you decide to launch this program automatically from ProSel-16
(as I do), ensure you change the file type to S16, otherwise ProSel
will always prompt you when it is done ... most annoying.
This program is in the public domain.
Devin Reade <gdr@myrias.com> January 1996.

View File

@ -1,52 +0,0 @@
.\" $Id: renram5.8,v 1.1 1996/01/29 06:20:11 gdr Exp $
.\"
.TH RENRAM5 8 "System Administration" "28 January 1996" "Version 1.0"
.SH NAME
renram5 \- rename /RAM5 at boot time
.SH SYNOPSIS
.BR renram5
[
.B \-d
] [
.I oldvolume
[
.I newvolume
]]
.SH DESCRIPTION
.BR renram5
is intended to be run automatically at boot time. It renames
the volume
.I oldvolume
to
.IR newvolume ,
if
.I newvolume
does not already exist. If
.I oldvolume
or
.I newvolume
aren't specified, they default to
.BR /RAM5
and
.BR /tmp .
.LP
If you are running
.BR renram5
automatically from ProSel-16 (and perhaps other launchers) you should
change the filetype to
.BR S16 .
This will keep ProSel from prompting after the program is finished.
When run as a
.BR S16
program, no command line arguments are possible.
.SH OPTIONS
.IP \fB-d\fP
Enable debugging information.
.SH AUTHOR
Devin Reade, <gdr@myrias.com>
.LP
This program is in the public domain.
.LP
This program contains material from the ORCA/C Run-Time
Libraries, copyright 1987-1996 by Byte Words, Inc.
Used with permission.

View File

@ -1,155 +0,0 @@
/*
* renram5
*
* This program is intended to be launched during boot time. It
* renames the volume /RAM5 to /tmp if /tmp does not already exist.
*
* It can also be invoked as a shell command (in which it should
* be changed to an exec file rather than a s16 file). As a shell
* command, its usage is:
* renram5 [-d] [ oldname [newname]]
*
* If <oldname> is not specified, it defaults to "/RAM5". If <newname> is
* not specified, it defaults to "/tmp". The -d flag enables debugging
* output.
*
* You probably need GNO/ME libraries in order to link this program.
*
* Written by Devin Reade <gdr@myrias.com> January 1996.
* This program is placed in the public domain.
*
* $Id: renram5.c,v 1.1 1996/01/29 06:20:12 gdr Exp $
*/
#include <types.h>
#include <gsos.h>
#include <orca.h>
#include <stdio.h>
#include <errno.h>
#include <stdlib.h>
#include <string.h>
#include <assert.h>
#ifndef P_tmpdir
#define P_tmpdir "/tmp"
#endif
#define OLD_TMP "/RAM5"
#define NEW_TMP P_tmpdir
extern GSString255Ptr __C2GSMALLOC(char *);
extern int _mapErr(int);
void usage(char *progname) {
printf("Usage: %s [-d] [oldvolume [newvolume]]\n",progname);
printf("\toldvolume defaults to %s\n",OLD_TMP);
printf("\tnewvolume defaults to %s\n",NEW_TMP);
printf("\t-d\tproduce debug information\n\n");
printf("This program renames volumes. It was intended to rename\n");
printf("%s at boot time. As a side effect, it can also rename files.\n\n",
OLD_TMP);
printf("Version 1.0 by Devin Reade <gdr@myrias.com>\n");
printf("This program is in the public domain.\n");
exit(1);
}
int main (int argc, char **argv) {
DevNumRecGS devrec;
ChangePathRecGS pathrec;
char *file1, *file2;
int i, filecount, debug;
filecount=0;
debug=0;
/* parse the command line, if any */
if (argc > 1) {
for (i=1; i<argc; i++) {
if (!strcmp(argv[i],"-d")) {
debug++;
} else if ((argv[i][0] == '-') || (filecount > 2)) {
usage(argv[0]);
} else if (filecount==0) {
file1 = argv[i];
filecount++;
} else if (filecount==1) {
file2 = argv[i];
filecount++;
} else assert(0);
}
}
switch (filecount) {
case 0:
file1 = OLD_TMP;
file2 = NEW_TMP;
break;
case 1:
file2 = NEW_TMP;
break;
case 2:
break;
default:
assert(0);
}
assert(file1);
assert(file2);
/*
* see if file2 is already around
*/
devrec.pCount = 2;
if ((devrec.devName = (GSString32Ptr) __C2GSMALLOC(file2)) == NULL) {
perror("couldn't duplicate destination volume name");
exit(1);
}
GetDevNumberGS(&devrec);
i=toolerror();
switch (i) {
case 0:
if (debug) {
printf("volume %s already exists on device %d\n",file2,
devrec.devNum);
}
exit(1);
case devNotFound:
case volNotFound:
/* this is what we're normally expecting */
break;
default:
fprintf(stderr,"couldn't get %s device number: %s\n",file2,
strerror(_mapErr(i)));
exit(1);
}
/*
* rename the volume
*/
pathrec.pCount = 3;
pathrec.pathname = __C2GSMALLOC(file1);
pathrec.newPathname = __C2GSMALLOC(file2);
pathrec.flags = 0;
if (!pathrec.pathname || !pathrec.newPathname) {
perror("couldn't duplicate volume names");
exit(1);
}
ChangePathGS(&pathrec);
i=toolerror();
switch (i) {
case 0:
if (debug) printf("device renamed\n");
break;
case pathNotFound:
case volNotFound:
if (debug) printf("device not renamed: %s\n",strerror(_mapErr(i)));
break;
default:
fprintf(stderr,"couldn't rename %s to %s: %s\n",file1, file2,
strerror(_mapErr(i)));
exit(1);
}
return 0;
}

View File

@ -1,10 +0,0 @@
Name: renram5
Version: 1.0
Shell: ORCA/Shell, GNO/ME
Author: Devin Reade
Contact: gdr@myrias.ab.ca
Where: /usr/sbin
FTP: ftp.cco.caltech.edu, grind.isca.uiowa.edu
Renames /RAM5 to /tmp on boot.

View File

@ -1,18 +0,0 @@
/*
* $Id: renram5.rez,v 1.1 1996/01/29 06:20:12 gdr Exp $
*/
#include "Types.Rez"
resource rVersion (0x1, purgeable3, nocrossbank) {
{ 1, 0, 0, /* version 1.0.0 */
release, /* development|alpha|beta|final|release */
0 /* non-final release number */
},
verBritain, /* close enough */
"renram5",
"Rename /RAM5 at boot time.\n"
"Devin Reade <gdr@myrias.com>\n"
"Canada"
};

View File

@ -1,33 +0,0 @@
Copyright 1996 Devin Reade <gdr@myrias.com>.
All rights reserved.
Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions
are met:
1. Redistributions of source code must retain the above copyright
notice, this list of conditions, and the following disclaimer.
2. Redistributions in binary form must reproduce the above copyright
notice, this list of conditions, and the following disclaimer
in the documentation and/or other materials provided with the
distribution. If the binary form is created using Orca/C, then
the following Byteworks' copyright notice must also be included
in the same location.
3. The name of the developer may not be used to endorse or promote
products derived from this software without specific prior
written permission.
THIS SOFTWARE IS PROVIDED BY THE DEVELOPER "AS IS" AND ANY EXPRESS
OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
ARE DISCLAIMED. IN NO EVENT SHALL THE DEVELOPER BE LIABLE FOR
ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE
GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY
OF SUCH DAMAGE.
The binary distribution of this program contains material from the Orca/C
Run-Time Libraries, copyright 1987-1996 by Byte Works, Inc. Used with
permission.

View File

@ -1,16 +0,0 @@
$Id: README,v 1.1 1996/09/03 03:54:55 gdr Exp $
As the describe file says, install(1) is a utility similar to cp(1),
except that it does a few more things and is intended for use in
makefiles and scripts.
To install install, type "dmake doinstall". By default, it places the
binary in /usr/bin and the man page in /usr/man/man1. If you don't
like these locations, either modify the makefile or copy the two files
by hand. There are no support files.
As usual, please email me or post to comp.sys.apple2.gno if you
encounter problems or bugs.
Devin Reade
March 1996

View File

@ -1,107 +0,0 @@
.\" Copyright 1996 Devin Reade <gdr@myrias.com>
.\"
.\" $Id: inst.1,v 1.1 1996/03/31 23:38:32 gdr Exp $
.\"
.TH INSTALL 1 "Commands and Applications" "31 Mar 96" "Version 1.0"
.SH NAME
install \- copy files and set their attributes
.SH SYNOPSIS
.BR install
[
.I options
] [
.BR -s
]
.I source
.I dest
.br
.BR install
[
.I options
] [
.BR -s
]
.I source
[ ... ]
.I directory
.br
.BR install
[
.I options
]
[
.BR -d
]
.I directory
[ ... ]
.SH DESCRIPTION
.BR install
copies files and sets their permission modes and, if possible, their
owner and group. It is used similarily to
.BR cp (1);
typically used in Makefiles to copy programs into their destination
directories. It can also be used to create the destination directories
and any leading directories, and to set the directories modes.
.LP
Some of the options listed below are not implemented or are implemented
in a restricted sense. Such options are recognised to maximize
.BR install 's
compatibility with other Unix versions, in order to minimize problems
with ported shell scripts and makefiles. Where options are not fully
implemented, it is usually due to differences between Unix and GS/OS.
.SH OPTIONS
.IP \fB-c\fR
Ignored. This option is included for backwards compatibility
with old Unix versions of
.BR install .
.IP \fB-d\fR
Create each given directory and its leading directories, if they
do not already exist.
.IP "\fB-g\fR \fIgroup\fR"
Set the group ownership of the installed file or directory to the group
ID of
.I group
(default is the processes current group).
.I group
may also be a numeric group ID.
.sp
\fBThis is currently ignored under GNO.\fR
.IP \fB-h\fR
Show usage information and exit.
.IP "\fB-m\fR \fImode\fR"
Set the permission mode for the installed file or directory to
.IR mode ,
which can be either an octal number, or a symbolic mode as in the
Unix chmod command,
with 0 as the point of departure. The default mode is 0755.
.sp
Note that currently under GNO, the
.I mode
is interpreted in the traditional Unix sense in that it only affects
read, write, and (to a limited extent) execute permissions.
Furthermore, the only bits interpreted are those for the
user permissions; the
.I mode
is effectively bitwise `anded' with the constant 0700.
.sp
An execute modification is only permitted when the original file
is of type TXT or SRC. If the `execute bit' is enabled, then
the file type will be changed to SRC and the auxilliary type to EXEC.
This is equivalent to making the file an executable shell script.
If the `execute bit' is disabled, then the file type will be changed
to TXT and the auxilliary type to 0x0000.
.IP "\fB-o\fR \fIowner\fR"
If run as root, set the ownership of the installed file to the user ID of
.IR owner .
.I owner
may also be numeric user ID.
.sp
\fBThis is currently ignored under GNO.\fR
.IP \fB-s\fR
Strip the symbol tables from the installed programs.
.sp
\fBThis is currently ignored under GNO.\fR
.IP \fB-v\fR
Show version number.
.SH AUTHOR
Devin Reade <gdr@eddore.myrias.com>

View File

@ -1,461 +0,0 @@
/*
* Copyright 1996 Devin Reade <gdr@myrias.com>.
* All rights reserved.
*
* For copying and distribution information, see the file "COPYING"
* accompanying this file.
*
* $Id: inst.c,v 1.2 1996/09/03 03:54:58 gdr Exp $
*/
#include <stdio.h>
#include <getopt.h>
#include <errno.h>
#include <ctype.h>
#include <stdlib.h>
#include <assert.h>
#include <string.h>
#include <types.h>
#include <unistd.h>
#include <sys/stat.h>
#include <orca.h>
#include <gsos.h>
extern int _mapErr(int);
#include "contrib.h"
/* actions */
#define NOCHANGE 0
#define ASSIGN 1
#define REMOVE 2
#define ADD 3
/* permissions */
#define S_USER 0700
#define S_GROUP 0070
#define S_OTHER 0007
#define S_ALL 0777
#define S_READ 0444
#define S_WRITE 0222
#define S_EXECUTE 0111
#define TYPE_TXT 0x04
#define TYPE_SRC 0xB0
#define TYPE_EXEC 0x00000006
#define TYPE_NONE 0x00000000
#define VERSION "1.0"
#define EMAIL "<gdr@myrias.com>"
char *versionMsg = "Version %s by Devin Reade %s\n";
int dFlag;
extern int mkdir(const char *);
extern int needsgno(void);
extern void begin_stack_check(void);
extern int end_stack_check(void);
/*
* usage
*
* display usage information and exit
*/
void
usage(void)
{
fputs("Usage: install [-cdhsv] [-o owner] [-g group] [-m mode] ", stderr);
fputs("source [...] dest\n\n", stderr);
fputs("Options:\n", stderr);
fputs("\t-c Ignored. (Backwards Unix compatibility)\n", stderr);
fputs("\t-d Create the specified directories\n", stderr);
fputs("\t-g group Specify group id (not implemented)\n", stderr);
fputs("\t-h Show usage information and exit.\n", stderr);
fputs("\t-m mode Specify (Unix) access mode\n", stderr);
fputs("\t-o owner Specify owner id (not implemented)\n", stderr);
fputs("\t-s Strip binary (not implemented)\n", stderr);
fputs("\t-v Show version number\n\n", stderr);
fprintf(stderr, versionMsg, VERSION, EMAIL);
exit(1);
}
/*
* getmode
*
* set mode to the value corresponding to the permission bit string
* <str>. If the first char of <str> is a digit, then it is assumed
* to be an octal number. Otherwise it is assumed to be a string of
* the form "ug+rx" (in the usual chmod(1) format). Also sets action
* to be the type of action to take, whether we're removing, adding,
* or assigning the permission bits.
*
* If these assumptions don't hold, then return non-zero. Returns
* zero and sets mode on success.
*
* Since the IIgs currently doesn't have the concept of "group" and
* "other" permissions, we take everything from the user permissions.
*/
int
getmode(char *str, unsigned long *mode, int *action)
{
unsigned long who = 0L;
unsigned long perm = 0L;
char *p, *q;
/* octal number? */
if (isdigit(*str)) {
*action = ASSIGN;
errno = 0;
*mode = strtoul(str, NULL, 8);
return errno;
}
/* it's not an absolute octal; treat as a string */
if (((p = strchr(str, '+')) == NULL) &&
((p = strchr(str, '-')) == NULL) &&
((p = strchr(str, '=')) == NULL)) {
errno = EINVAL;
return errno;
}
switch (*p) {
case '+': *action = ADD; break;
case '-': *action = REMOVE; break;
case '=': *action = ASSIGN; break;
default: assert(0);
}
/*
* this condition should really be deduced from the umask, if it
* were supported.
*/
if (str == p) {
who |= S_USER;
}
for (q = str; q < p; q++) {
switch (*q) {
case 'u': who |= S_USER; break;
case 'g': who |= S_GROUP; break;
case 'o': who |= S_OTHER; break;
case 'a': who |= S_ALL; break;
default: errno = EINVAL; return errno;
}
}
for (q = p + 1; *q; q++) {
switch (*q) {
case 'r': perm |= S_READ; break;
case 'w': perm |= S_WRITE; break;
case 'x': perm |= S_EXECUTE; break;
case 's': /* ignored */ break;
default: errno = EINVAL; return errno;
}
}
/* currently: ignore all but user permissions */
if (!(who & S_USER)) {
*action = NOCHANGE;
}
*mode = who & perm;
return 0;
}
/*
* mkdirs
*
* argv is assumed to be an array of argc pathnames. mkdirs will
* create all the listed directories, including their parents if
* necessary.
*
* Returns zero on success. Returns non-zero and prints a suitable
* error message on failure.
*/
int
mkdirs(int argc, char **argv)
{
static struct stat statbuf; /* reduce stack space */
char *path, *p;
size_t pathlen;
int result = 0;
int makeit; /* do we try a mkdir()? */
int abortpath; /* we saw an error; don't both with rest of path */
int i, j;
int coloncount;
/* loop over each of the pathnames in the array */
for (i = 0; i < argc; i++) {
/* expand to a full pathname */
if ((path = expandpath(argv[i])) == NULL) {
perror(argv[i]);
continue;
}
pathlen = strlen(path);
/* is this pathname legal? */
/* place a call to JudgeName() [custom] here */
/* find out how many path components there are */
coloncount = 0;
p = path;
while (*p) {
if (*p == ':') {
coloncount++;
}
p++;
}
p = path + 1;
/* skip the volume name */
if ((p = strchr(p, ':')) == NULL) {
/* only the volume name was given; skip it */
free(path);
continue;
}
p++;
--coloncount;
/* create each component in path */
abortpath = 0;
for (j = 0; !abortpath && j < coloncount; j++) {
if ((p = strchr(p, ':')) == NULL) {
p = path + pathlen;
}
*p = '\0';
if (stat(path, &statbuf) != 0) {
if (errno == ENOENT) {
makeit = 1;
} else {
perror(path);
makeit = 0;
abortpath = 1;
result = 1;
}
} else {
makeit = 0;
if (statbuf.st_mode & S_IFDIR == 0) {
fprintf(stderr, "%s exists and is not a directory\n", path);
abortpath = 1;
result = 1;
} /* else it exists and is a directory */
}
/* go ahead and create the directory */
if (makeit && mkdir(path)) {
perror(path);
abortpath = 1;
result = 1;
}
/* reinstate the ':' that we "nulled-out" */
if (p != path + pathlen) {
*p++ = ':';
}
}
free(path);
}
return result;
}
/*
* copyfiles
*
* <argv> is assumed to be an array of <argc> filenames.
*
* This routine copies all but the last specified file to the directory
* or filename specified by the last filename. If argc>2, the last element
* _must_ be a directory.
*
* Returns zero on success. On failure, returns the last non-zero errno
* and prints error conditions to stderr.
*
* If action is not NOCHANGE, this routine will also set file permissions
* as specified in the install(1) man page. This may involve changing
* the file type.
*/
static int
copyfiles(int argc, char **argv, int action, unsigned long mode)
{
static FileInfoRecGS inforec;
static GSString255 filenameGS;
int i, j;
int result = 0;
char *destination;
Word newaccess;
if (argc < 2) {
errno = EINVAL;
perror("internal error: not enough arguments to copyfiles()");
return errno;
}
if (argc > 2) {
/* find out if argv[argc-1] is a directory */
if (__C2GS(argv[argc - 1], &filenameGS) == NULL) {
errno = EINVAL;
perror("destination path too long");
return errno;
}
inforec.pCount = 5;
inforec.pathname = &filenameGS;
GetFileInfoGS(&inforec);
if ((errnoGS = toolerror()) != 0) {
perrorGS("%s", argv[argc - 1]);
errno = _mapErr(errnoGS);
return -1;
}
if ((inforec.storageType != 0x0D) && (inforec.storageType != 0x0F)) {
errno = ENOTDIR;
perror(argv[argc - 1]);
return errno;
}
}
--argc;
for (i = 0; i < argc; i++) {
if ((destination = copyfile(argv[i], argv[argc])) == NULL) {
errnoGS = toolerror();
perrorGS("install of %s to %s", argv[i], argv[argc]);
result = errno = _mapErr(errnoGS);
}
if (action == NOCHANGE) {
continue;
}
/* get the file info for the source file */
if (__C2GS(argv[i], &filenameGS) == NULL) {
assert(0);
}
inforec.pCount = 7;
inforec.pathname = &filenameGS;
GetFileInfoGS(&inforec);
if ((errnoGS = toolerror()) != 0) {
perrorGS("GetFileInfo for %s failed", argv[i]);
result = errno = _mapErr(errnoGS);
}
/* modify the permissions as necessary */
switch (action) {
case ASSIGN:
newaccess = 0xFFFF;
if (!(mode & S_READ)) newaccess &= ~readEnable;
if (!(mode & S_WRITE)) newaccess &= ~writeEnable;
inforec.access &= newaccess;
if ((mode & S_EXECUTE) &&
(inforec.fileType == TYPE_TXT) || (inforec.fileType == TYPE_SRC)) {
inforec.fileType = TYPE_SRC;
inforec.auxType = TYPE_EXEC;
}
break;
case ADD:
if (mode & S_READ) inforec.access |= readEnable;
if (mode & S_WRITE) inforec.access |= writeEnable;
if ((mode & S_EXECUTE) &&
(inforec.fileType == TYPE_TXT) || (inforec.fileType == TYPE_SRC)) {
inforec.fileType = TYPE_SRC;
inforec.auxType = TYPE_EXEC;
}
break;
case REMOVE:
if (mode & S_READ) inforec.access &= ~readEnable;
if (mode & S_WRITE) inforec.access &= ~writeEnable;
if ((mode & S_EXECUTE) &&
(inforec.fileType == TYPE_TXT) || (inforec.fileType == TYPE_SRC)) {
inforec.fileType = TYPE_TXT;
inforec.auxType = TYPE_NONE;
}
break;
default:
assert(0);
}
/* set the modified file info for the destination file */
if (__C2GS(destination, &filenameGS) == NULL) {
assert(0);
}
SetFileInfoGS(&inforec);
if ((errnoGS = toolerror()) != 0) {
perrorGS("SetFileInfo for %s failed", destination);
result = errno = _mapErr(errnoGS);
}
}
return result;
}
/*
* obvious ...
*/
int
main(int argc, char **argv)
{
unsigned long mode;
int c, nfiles;
int action = NOCHANGE;
#ifdef CHECK_STACK
begin_stack_check();
#endif
if (needsgno() == 0) {
fprintf(stderr, "Requires GNO/ME\n");
exit(1);
}
/* initialize */
dFlag = 0;
mode = 0L;
/* parse command line */
while ((c = getopt(argc, argv, "cdg:hm:o:sv")) != EOF) {
switch (c) {
case 'v':
fprintf(stderr, versionMsg, VERSION, EMAIL);
exit(1);
break;
case 'm':
if (getmode(optarg, &mode, &action)) {
usage();
}
break;
case 'd': dFlag++;
case 'c': /* not implemented */
case 'g': /* not implemented */
case 'o': /* not implemented */
case 's': /* not implemented */
break;
case 'h':
default: usage();
}
}
nfiles = argc - optind;
if (dFlag) {
if (nfiles < 1) {
usage();
}
c = mkdirs(nfiles, &argv[optind]);
} else {
if (nfiles < 2) {
usage();
}
c = copyfiles(nfiles, &argv[optind], action, mode);
}
#ifdef CHECK_STACK
fprintf(stderr, "stack usage: %d bytes\n", end_stack_check());
#endif
return c;
}

View File

@ -1,12 +0,0 @@
Name: install
Version: 1.0 (31 Mar 96)
Shell: GNO/ME
Author: Devin Reade
Contact: gdr@myrias.com
Where: /usr/bin
FTP: apple2.caltech.edu, ground.isca.uiowa.edu
Install is similar to cp(1) in that it copies files. It will
also create directory hierarchies, and modify some access bits.
It is intended for use with Makefiles or other scripts to install
files into their destination directories.

View File

@ -1,25 +0,0 @@
/*
* Copyright 1996 Devin Reade <gdr@myrias.com>.
* All rights reserved.
*
* For copying and distribution information, see the file "COPYING"
* accompanying this file.
*
* $Id: inst.rez,v 1.1 1996/03/31 23:38:34 gdr Exp $
*/
#include "Types.Rez"
resource rVersion (0x1, purgeable3, nocrossbank) {
{ 1, 0, 0, /* version 1.0.0 */
release, /* development|alpha|beta|final|release */
0 /* non-final release number */
},
verBritain, /* close enough */
"install",
"Unix-style install program --\n"
" copies files and creates directories\n"
"Devin Reade <gdr@myrias.com>\n"
"Canada"
};

View File

@ -1,31 +0,0 @@
#
# This makefile is for use with dmake(1).
#
# $Id: makefile.mk,v 1.2 1996/09/03 03:54:59 gdr Exp $
#
DEFINES = -D__GNO__ # -DCHECK_STACK
INCLUDES = -I ../contrib/src
STACK = -s1280
CFLAGS = $(DEFINES) $(INCLUDES) $(STACK) -w -O -v
LDFLAGS = -v
LDLIBS = -l ../contrib/src/lcontrib \
-l ../contrib/src/libc2 \
# -l/usr/lib/stack
BINDIR = /usr/bin
MANDIR = /usr/man
OBJS = install.o
install: $(OBJS) install.r
$(CC) $(LDFLAGS) $(OBJS) $(LDLIBS) -o $@
copyfork install.r install -r
@echo 'type \"dmake doinstall\" to install this program'
doinstall:
./install -d $(BINDIR) $(MANDIR)/man1
./install -m755 -obin -gsys ./install $(BINDIR)
./install -m644 -obin -gsys ./install.1 $(MANDIR)/man1
clean clobber:
$(RM) $(OBJS) install.root install.r

View File

@ -1,209 +0,0 @@
--------------------------------------------
Name: manpack
Version: 3.0
Author: Devin Reade <gdr@myrias.com>
Computer: Apple IIgs
Requires: GNO v2.x
--------------------------------------------
===========
Description:
===========
Various programs for working with manual pages. This archive includes:
apropos v3.0 locate commands by keyword
catman v1.0 format cat pages from man pages
makewhatis v1.2 create the whatis database
man v3.0 display reference manual pages
whatis v3.0 locate commands by name
============
Installation:
============
Type at the command line `dmake install`. You may wish to first
verify the destination directories in "Makefile.mk". By default
these are:
BINDIR = /usr/bin (apropos, catman, man, and whatis)
SBINDIR = /usr/sbin (makewhatis)
MANDIR = /usr/man (all manual pages)
Ensure that all older versions of these programs are deleted.
They may or may not be in the above directories.
==========
Legalities:
==========
These utilities are copyright 1995 by Devin Reade <gdr@myrias.com>.
They are provided as freeware, and may be distributed by Internet
archive sites, online services such as GEnie, or BBSes provided that
the archive remains intact. Permission is granted for distribution
with GNO/ME and Orca provided credit for this work is given along
with any other attributions.
Inclusion of these utilities in collections on disk, CD-ROM, or
other portable media is permitted provided that only a nominal
fee (not much more than the media cost) is charged. Contact the
author regarding other commercial distributions.
Updates to these utilities may be distributed provided that the source
and this README file are included. Please follow the coding style
already in use and document your changes in this file.
=======
CHANGES:
=======
apropos, whatis
v3.0 (24 Jul 95)
Complete rewrite from scratch by Devin Reade.
This version makes use of MANPATH in the same way
as man(1) v3.0. Similarily, it will also search
the 17/syscmnd Orca database.
In the previous version, the behavior of apropos was
identical to that of whatis. This version has been
fixed so that whatis is case sensitive and searches
only the manual page names. The apropos search is
case insensitive and searches the entire database
entry.
v2.1 (1 Jul 92 ?)
This version is by Mike Horwath and shipped with GNO v1.1.
Although no version flags or resource forks where provided
with this release, this release is designated as v2.1
because it shipped with man(1) v2.1.
catman
v1.0 (24 Jul 95)
Initial release. Written from scratch by Devin Reade.
makewhatis
v1.2 (24 Jul 95)
Fixed bug where pages in "manl" ending in ".l" (that's
"ell" in both cases) would be ignored.
Added recognition of files compressed with gzip.
File compression suffixes are now case sensitive.
If none of MANPATH, USRMAN, or MANDIR are defined,
"/usr/man" will now be used.
Fixed a bug where the word SYNOPSIS appearing in the
description would mangle the database entry.
Added a verbose-level-three flag (-v3), which is basically
the old -v2 flag. The new -v2 is somewhat less verbose
than it was.
v1.1 (29 May 94)
Makewhatis will now ignore any man page starting with
".so", in order to eliminate multiple files. The resultant
blank lines in the whatis database have therefore been
eliminated.
Changed -v flag to {-v1|-v2} for differing stages of verbosity.
Only error output will be logged with the -l flag.
Manual page was updated, to include a correction to the -o
flag usage and the modification to the -v flag. Descriptions
of bugs unlikely to be fixed were added. Date and version
were changed.
Fixed bug where input buffer wasn't properly terminated, and
added checks for buffer overflows.
Makewhatis will now display all commands about which the
manual page is written. For example, if foo.1 described
both foo(1) and bar(1), and bar.1 was an .so (or .l) link
to foo.1, then the database entry will have changed from
foo (1) - extract and add thingys
foo, bar (1) - extract and add thingys
Makewhatis used to pick up the first NAME string in the file
as a reference point. Now, any NAME is ignored in any line
starting with .\" or .TH
Filename chapter numbers will now be correctly extracted
regardless of the existence of .Z, .z, .F, or .f suffixes,
or of the existence of '.' within the base file name.
Makewhatis is now linked with Soenke's gnulib for the
getopt() function, rather than using the libc version.
Stack usage was reduced to 1k. Be aware, though, that a
fair amount of global storage is used, including three 1k
buffers.
v1.0 (15 May 94)
Initial release. Written from scratch by Devin Reade.
man
v3.0 (24 Jul 95)
Complete rewrite from scratch by Devin Reade.
The -k, -t, -, -f, -M, and -T flags were added.
Man now supports the MANPATH environment variable which
can be a list of paths delimited by either colons or
spaces.
Added sections 3f, l, n, o, and p to searched subdirectories.
Added gzip(1) to compress(1) and freeze(1) as allowable
source compressors.
Fixed bug with the .so source command; .so references
should now (properly) appear as ".so man<section>/<filename>"
instead of using the full pathname.
Updates to apropos v3.0 apply to man when invoked with
the -k flag.
Preprocessing by eqn(1), refer(1), tbl(1), and vgrind(1)
is not yet supported.
v2.1 (1 Jul 92 ?)
Recognised environment variable USRMAN as well as MANDIR.
This version was also by Mike Horwath.
v2.0 (Date Unknown)
This version is by Mike Horwath and shipped with GNO v1.1.
It made use of the environment variable MANDIR which had
to be a single directory.
=====
TO DO:
=====
Makewhatis is not very well integrated with the rest of the package;
there is still duplication of definitions and functions in some files.
Man, catman, and makewhatis need to support preformatting for eqn(1),
vgrind(1), et al.
Makewhatis' "verbose" output could be cleaner.
Performance analysis has not been done. No doubt some things could
improve, including some string matching in util.c
If the stock getenv(3) function is used (as is done here), then the
return value should be duplicated (via strdup) rather than just used.
If the getenv function from the lenviron library is used, this is not
a concern.
Perhaps an "X" version should be done for the Second Sight card. This
will have to wait a while.

View File

@ -1 +0,0 @@
.so man1/whatis.1

View File

@ -1,110 +0,0 @@
/*
* Copyright 1995 by Devin Reade <gdr@myrias.com>. For distribution
* information see the README file that is part of the manpack archive,
* or contact the author, above.
*/
segment "apropos___";
#include <stdio.h>
#include <getopt.h>
#include <stdlib.h>
#include <libc.h>
#include "util.h"
#include "man.h"
extern int optind;
extern char *optarg;
static char *versionstr = "3.0";
static char *nothing = "nothing appropriate";
extern void begin_stack_check(void);
extern int end_stack_check(void);
int main (int argc, char **argv) {
char *path;
int i, matches1, matches2, matches3;
short V_flag, M_flag, m_flag, n_flag, err_flag;
/* make sure Gno is running */
if (needsgno()==0) {
fprintf(stderr,"Requires Gno/ME\n");
return 1;
}
#ifdef STACK_CHECK
begin_stack_check();
#endif
/* initialization */
V_flag = M_flag = m_flag = n_flag = err_flag = 0;
matches1 = matches2 = matches3 = 0;
/* parse command line and check usage */
while((i = getopt(argc,argv,"M:m:nV")) != EOF) {
switch(i) {
case 'M':
if (m_flag) err_flag++;
M_flag++;
path = optarg;
break;
case 'm':
if (M_flag) err_flag++;
m_flag++;
path = optarg;
break;
case 'n':
n_flag++;
break;
case 'V':
V_flag++;
break;
default:
err_flag++;
}
}
if (argc-optind < 1) err_flag++;
if (err_flag || V_flag) {
fprintf(stderr,"%s version %s by Devin Reade\n",
basename(argv[0]),versionstr);
}
if (err_flag) {
fprintf(stderr,
"Usage: %s [[-M path] | [-m path]] [-nV] keyword [keyword ...]\n",
basename(argv[0]));
return 1;
}
/* do the search */
if (M_flag) {
manpath = path;
} else {
manpath = getManpath();
}
matches1 = apropos(argc-optind, &argv[optind], MAN_K_MODE);
if (!M_flag) free(manpath);
if (m_flag) {
manpath = path;
matches2 = apropos(argc-optind, &argv[optind], MAN_K_MODE);
}
if (!n_flag) {
matches3 = apropos(argc-optind, &argv[optind], ORCA_K_MODE);
}
i = 0;
if (matches1>0) i+= matches1;
if ( m_flag && matches2>0) i+=matches2;
if (!n_flag && matches3>0) i+=matches3;
if (i==0) {
fprintf(stderr,"%s: %s\n",basename(argv[0]),nothing);
}
#ifdef STACK_CHECK
fprintf(stderr,"stack usage: %d bytes\n",end_stack_check());
#endif
if ((matches1>=0) && (matches2>=0) && (matches3>=0) && i>0) return 0;
return 1;
}

View File

@ -1,284 +0,0 @@
/*
* Copyright 1995 by Devin Reade <gdr@myrias.com>. For distribution
* information see the README file that is part of the manpack archive,
* or contact the author, above.
*/
segment "apropos2__";
#include <stdio.h>
#include <unistd.h>
#include <errno.h>
#include <string.h>
#include <assert.h>
#include <stdlib.h>
#include <ctype.h>
#include "util.h"
#include "man.h"
/*
* orcapadding -- return a suitable number of padding tabs based on the
* length of the command
*/
static char *orcapadding (char *command) {
int i;
static char *two ="\t\t";
static char *one ="\t";
static char *zero =" ";
i = strlen(command);
if (i<8) return two;
if (i<16) return one;
return zero;
}
/*
* orcacomment -- return the start of the comment field in a line of
* the Orca SYSCMND file. This _must_ be called before
* orcacommand() is called on the same buffer, because
* orcacommand() modifies the buffer.
*/
static char *orcacomment (char *buffer) {
char *p;
static char *bad_line="malformed SYSCMND line\n";
p = buffer;
/* get past the command name */
while ((*p != ' ') && (*p != '\t') && *p) p++;
if (!*p) return bad_line;
/* get past space */
while ((*p == ' ') || (*p == '\t') && *p) p++;
if (!*p) return bad_line;
if (*p == '*') p++;
switch (*p) {
case 'U': /*FALLTHROUGH*/
case 'u':
p++;
break;
case 'C': /*FALLTHROUGH*/
case 'L': /*FALLTHROUGH*/
case 'c': /*FALLTHROUGH*/
case 'l':
p++;
/* get past space */
while ((*p == ' ') || (*p == '\t') && *p) p++;
if (!*p) return bad_line;
/* get past command or language number */
while (isdigit(*p)) p++;
break;
default:
return bad_line;
break;
}
/* get past any remaining space */
while ((*p == ' ') || (*p == '\t')) p++;
if (!*p) return bad_line;
return p;
}
/*
* orcacommand -- returns the command name that starts the buffer.
* This _must_ be called after orcacomment because it
* modifies the buffer.
*/
static char *orcacommand(char *buffer) {
char *p;
p = buffer;
while (*p && !isspace(*p)) p++;
*p = '\0';
return buffer;
}
/*
* apropos -- print matching lines from WHATIS database. Returns the
* number of matching lines, or -1 on error.
*
* Argv is an array of argc strings, each of which is a keyword.
* Apropos will print out any line that matches any of the
* keywords in argv. The match algorithm depends on the value
* of apropos_mode, which may be one of the following. For the
* first three modes, global variable <manpath> must be set.
*
* MAN_K_MODE -- this is the one used by apropos(1). A
* match is considered to be made if the keyword
* appears anywhere in the WHATIS database line.
* The match is case insensitive.
*
* MAN_F_MODE -- Any leading path component is stripped from
* the keywords, and then a match is attempted
* for any part of the WHATIS database line. The
* match is case insensitive.
*
* WHATIS_MODE -- The WHATIS database line is parsed up to the
* first occurance of a '(' character. If any
* of the keywords are found, then the line is
* printed. The search is case sensitive.
*
* ORCA_K_MODE -- Like MAN_K_MODE but instead of checking
* the various WHATIS databases, it checks
* 15/syscmnd.
*
* ORCA_W_MODE -- Like WHATIS_MODE but instead of checking
* the various WHATIS databases, it checks
* 15/syscmnd.
*
* WARNING: Use of the MAN_F_MODE may alter the contents of argv[].
*/
int apropos(int argc, char **argv, int apropos_mode) {
char **manpath_array;
char *current_path, *p, *q, *r, *keyword;
FILE *fp;
char dirbrk;
int i, j, matches;
#ifdef DEBUG
assert ((apropos_mode == WHATIS_MODE) ||
(apropos_mode == MAN_K_MODE) ||
(apropos_mode == MAN_F_MODE) ||
(apropos_mode == ORCA_K_MODE) ||
(apropos_mode == ORCA_F_MODE) ||
(apropos_mode == ORCA_W_MODE));
#endif
matches = 0;
/*
* if we're doing 'man -f', get the basename for all keywords
*/
if ((apropos_mode == MAN_F_MODE) || (apropos_mode == ORCA_F_MODE)) {
for (i=0; i<argc; i++) {
dirbrk = (strchr(argv[i],':')!=NULL) ? ':' : '/';
if ((q = strrchr(argv[i],dirbrk)) != NULL) {
q++;
p = argv[i];
do {
*p = *q;
p++; q++;
} while (*q);
*p = '\0';
}
}
}
if ((apropos_mode == ORCA_K_MODE) ||
(apropos_mode == ORCA_W_MODE) ||
(apropos_mode == ORCA_F_MODE)) {
/*
* searching the Orca 15/syscmnd file
*/
if ((fp = fopen(SYSCMND,"r")) == NULL) {
fprintf(stderr,"couldn't open %s\n",SYSCMND);
return -1;
}
/* loop over lines in file */
while ((q = fgets(linebuf,BUFFERSIZE,fp)) != NULL) {
if (*linebuf == ';') continue;
/* loop over keywords */
for(i=0; i<argc; i++) {
keyword = argv[i];
if ((apropos_mode == ORCA_K_MODE && ncstrstr(linebuf,keyword)) ||
(apropos_mode == ORCA_F_MODE && strstr(linebuf,keyword)) ||
(apropos_mode == ORCA_W_MODE &&
!strncmp(linebuf,keyword,strlen(keyword)))) {
r = orcacomment(linebuf);
p = orcacommand(linebuf);
q = orcapadding(p);
printf("%s (Orca) %s- %s",p,q,r);
matches++;
}
}
}
fclose(fp);
return matches;
}
if ((manpath_array = makePathArray(manpath)) == NULL) return -1;
/*
* loop over all the paths in MANPATH
*/
i=0;
current_path = manpath_array[i];
while (current_path) {
dirbrk = (strchr(current_path,':')!=NULL) ? ':' : '/';
if (chdir(current_path) == -1) {
fprintf(stderr,"%s: %s\n",current_path,strerror(errno));
} else if ((fp=fopen(WHATIS,"r"))==NULL) {
if (access(WHATIS,F_OK) == -1) {
fprintf(stderr,"%s%c%s: %s\n",current_path,dirbrk,WHATIS,
strerror(ENOENT));
} else {
fprintf(stderr,"error opening %s%c%s\n",current_path,dirbrk,
WHATIS);
}
} else {
/* read each line, looking for a match */
for (;;) {
q = fgets(linebuf,BUFFERSIZE,fp);
if (q != NULL) {
/* search for a match to any keyword */
for (j=0; j<argc; j++) {
keyword = argv[j];
switch (apropos_mode) {
case MAN_F_MODE:
if (strstr(linebuf,keyword)) {
printf("%s",linebuf);
matches++;
}
break;
case MAN_K_MODE:
if (ncstrstr(linebuf,keyword)) {
printf("%s",linebuf);
matches++;
}
break;
case WHATIS_MODE:
/* avoid unnecessary strcpy's */
if (strstr(linebuf,keyword)==NULL) break;
strcpy(linebuf2,linebuf);
if ((p = strchr(linebuf2,'(')) != NULL) *p = '\0';
if (strstr(linebuf2,keyword)) {
printf("%s",linebuf);
matches++;
}
break;
default:
fprintf(stderr,"internal error line %d of %s\n",
__LINE__,__FILE__);
exit(1);
}
}
} else if (ferror(fp)) {
fprintf(stderr,"error reading %s database: %s\n",WHATIS,
strerror(errno));
break;
} else break;
}
fclose(fp);
}
i++;
current_path = manpath_array[i];
} /* endwhile loop over directories */
return matches;
}

View File

@ -1,95 +0,0 @@
.\" Copyright (c) 1995 Devin Reade <gdr@myrias.com>. All rights reserved.
.\"
.TH CATMAN 8 "System Administration" "24 July 95" "Version 1.0"
.SH NAME
catman \- format cat pages from man pages
.SH SYNOPSIS
.BR catman
[
.B -pvV
] [[
.BI -M path
] | [
.BI -m path
]] [
.IR section " ..."
]
.SH DESCRIPTION
.BR catman
creates formatted versions of the on-line manual pages from their
.BR nroff (1)
or
.BR aroff (1)
source.
Manual pages whose formatted versions are missing or out of date are
regenerated.
.LP
If
.IR section
is specified, then
.BR catman
will only created formatted manual pages for the specified
.IR section (s).
.LP
Manual pages that are
.BR nroff (1)
source and are compressed with either
.BR compress (1),
.BR freeze (1),
or
.BR gzip (1)
are recognised provided that they have the suffixes
.BR ".Z" ,
.BR ".F" ,
and
.BR ".gz" ,
respectively. Manual page names, including suffixes, are case sensitive.
.LP
Preformatted manual pages will be created in
.BI cat ?
only if that subdirectory exists.
.SH OPTIONS
.IP \fB-p\fP
Display the commands that would have been executed, but do not actually
execute them.
.IP "\fB-M\fR \fIpath\fR"
Set
.I path
to be the list of paths for which manual pages will be updated.
If not set, the value of
.BR MANPATH ,
.BR USRMAN ,
or
.BR MANDIR
will be used instead. Multiple directories may be specified by
separating them either by colons or by spaces. In the latter case,
be sure to quote
.I path
from the shell.
.IP "\fB-m\fR \fIpath\fR"
Append
.I path
on to the list of paths for which manual pages will be updated.
.IP \fB-V\fR
Display version information and exit.
.IP \fB-v\fR
Verbose. Show processing information.
.SH BUGS
Please report any bugs to Devin Reade, <gdr@myrias.ab.ca>.
.SH SEE ALSO
.BR apropos (1),
.BR man (1),
.BR whatis (1),
.BR gzip (1),
.BR compress (1),
.BR freeze (1),
.BR makewhatis (8).
.SH WARNING
.BR catman
will unlink any out-of-date files in the
.BI cat ?
subdirectories. The files that would be unlinked are listed when
.BR catman
is invoked with the
.BR -p
option.

View File

@ -1,356 +0,0 @@
/*
* Copyright 1995 by Devin Reade <gdr@myrias.com>. For distribution
* information see the README file that is part of the manpack archive,
* or contact the author, above.
*/
segment "catman____";
#include <sys/types.h>
#include <stdio.h>
#include <getopt.h>
#include <stdlib.h>
#include <unistd.h>
#include <libc.h>
#include <dirent.h>
#include <string.h>
#include <stdlib.h>
#include <assert.h>
#include <sys/stat.h>
#include <errno.h>
#include "util.h"
#include "man.h"
#define OVERFLOW_ABORT(line,file) { \
fprintf(stderr,overflowMsg,line,file); \
exit(1); \
}
short v_flag, V_flag, M_flag, m_flag, p_flag, err_flag;
extern int optind;
extern char *optarg;
static char *versionstr = "1.0";
/* This is of the form "man<section>" */
char mandir[FILENAME_MAX];
/*
* These are of the form
* "(man|cat)<section>/<name>.<section>[.<compression_suffix>]"
*/
char manfile[FILENAME_MAX];
char catfile[FILENAME_MAX];
char catfile2[FILENAME_MAX];
char base[FILENAME_MAX];
static char *overflowMsg = "internal buffer overflow at line %d of %s\n";
extern void begin_stack_check(void);
extern int end_stack_check(void);
/*
* catman
*
* Pre: argv is an array of section numbers (character strings), possibly
* empty.
* argc is the number of entries in argv.
* global variable <manpath> is a space- or colon-delimited list
* of pathnames.
*
* Post: for each pathname in <manpath>, catman will preformat the manpages
* within the man* subdirectories and place the result in the
* corresponding cat* subdirectory. If section numbers are specified,
* only those sections will be done.
*
* Returns 0 on success, 1 on failure.
*/
int catman(int argc, char **argv) {
char **manpath_array; /* MANPATH components in array form */
char *current_path; /* the current MANPATH component */
int i; /* an index */
int pathIndex; /* offset into manpath_array[] */
int sectionIndex; /* offset into sections[] */
DIR *manp, *catp; /* directory pointers */
struct dirent *entp; /* current file entry in manp */
char *sec; /* the current section "number" */
int catfile_found; /* have we found a preformatted version */
/* that's newer than the unformatted version? */
fileType *ftype; /* the file type of the man page */
struct stat statbuf1, statbuf2;
char dirbrk;
/* create array of paths to search */
if ((manpath_array = makePathArray(manpath)) == NULL) return 1;
/* loop over paths in MANPATH */
pathIndex=0;
current_path = manpath_array[pathIndex];
while(current_path) {
dirbrk = (strchr(current_path,':')==NULL) ? '/' : ':';
/* go to the current path in MANPATH */
if (v_flag) printf("cd %s\n",current_path);
if (chdir(current_path) == -1) {
pathIndex++;
current_path = manpath_array[pathIndex];
continue;
}
/* loop over sections */
for (sectionIndex=0; sections[sectionIndex].name!=NULL; sectionIndex++){
/*
* if section number was specified and this isn't it, do
* the next loop
*/
if (argc > 0) {
sec = NULL;
for (i=0; i<argc; i++) {
if (!strcmp(argv[i],sections[sectionIndex].name)) {
sec = argv[i];
break;
}
}
if (sec == NULL) continue;
} else sec = sections[sectionIndex].name;
#ifdef DEBUG
assert(sec);
#endif
/*
* we're going to update this section. Open the man? subdir
*/
if (strlen(sec) + 3 >= FILENAME_MAX) {
OVERFLOW_ABORT(__LINE__,__FILE__);
}
sprintf(mandir,"man%s",sec);
if ((manp = opendir(mandir)) == NULL) continue;
/* make sure the cat? directory exists, but leave it closed */
sprintf(catfile,"cat%s",sec);
if ((catp = opendir(catfile)) == NULL) {
closedir(manp);
continue;
} else {
closedir(catp);
}
/* loop over files in this section */
while ((entp = readdir(manp)) != NULL) {
/* skip standard file entries */
if (!strcmp(entp->d_name,".") || !strcmp(entp->d_name,"..")) {
continue;
}
/*
* make the base the name of the man? entry excluding
* any compression suffix
*/
strcpy(base,entp->d_name);
for (i=0; compressArray[i].suffix != NULL; i++) {
size_t len1, len2;
len1 = strlen(compressArray[i].suffix);
len2 = strlen(base);
if (!strcmp(compressArray[i].suffix,
(char *)(base + len2 - len1))) {
*(base + len2 - len1) = '\0';
break;
}
}
/*
* set manfile and catfile properly
*/
sprintf(manfile,"man%s%c%s",sec,dirbrk,entp->d_name);
sprintf(catfile,"cat%s%c%s",sec,dirbrk,base);
if (stat(manfile,&statbuf1) != 0) {
fprintf(stderr,"stat on %s failed: %s: file skipped\n",
manfile, strerror(errno));
continue;
}
/*
* search for an uncompressed file in the cat? directory,
* unlinking any older files.
*/
catfile_found=0;
if (stat(catfile,&statbuf2) == 0) {
if (statbuf1.st_mtime <= statbuf2.st_mtime) {
catfile_found++;
} else {
if (v_flag) printf("rm %s%c%s\n",current_path,dirbrk,catfile);
if (!p_flag) unlink(catfile);
}
}
/*
* search for any compressed files in the cat? directory,
* unlinking any older files.
*/
for(i=0;compressArray[i].suffix != NULL; i++) {
sprintf(catfile2,"cat%s%c%s%s",sec,dirbrk,base,
compressArray[i].suffix);
if (stat(catfile2,&statbuf2) == 0) {
if ((!catfile_found) &&
(statbuf1.st_mtime <= statbuf2.st_mtime)) {
strcpy(catfile,catfile2);
catfile_found++;
} else {
if (v_flag)
printf("rm %s%c%s\n",current_path,dirbrk,catfile2);
if (!p_flag) unlink(catfile2);
}
}
}
if (catfile_found) continue;
/*
* If we got to this point, then we will be preformatting
* the manual page. There is also no version of the man
* page left in cat?.
*/
sprintf(catfile,"cat%s%c%s",sec,dirbrk,base);
i = getSuffixIndex(manfile);
if (i >= 0) {
if (strlen(compressArray[i].extractor) + strlen(manfile) +
strlen(NROFF) + strlen(catfile) + 14 >= BUFFERSIZE) {
OVERFLOW_ABORT(__LINE__,__FILE__);
}
sprintf(linebuf,"%s %s | %s -man - > %s",
compressArray[i].extractor,manfile,NROFF,catfile);
} else {
/* determine which roffer to use based on the file type */
if ((ftype = getFileType(manfile)) == NULL) {
fprintf(stderr,"getFileType failed for %s: %s\n",
manfile,strerror(errno));
continue;
}
if ((ftype->type == 0x50) && (ftype->auxtype == 0x8010)) {
if (strlen(AROFF) + strlen(manfile) + strlen(catfile)
>= BUFFERSIZE) {
OVERFLOW_ABORT(__LINE__,__FILE__);
}
sprintf(linebuf,"%s %s > %s",AROFF,manfile,catfile);
} else if ((ftype->type == TXT) || (ftype->type == BIN) ||
(ftype->type == SRC) || (ftype->type == NON)) {
if (strlen(NROFF) + strlen(manfile) + strlen(catfile)
>= BUFFERSIZE) {
OVERFLOW_ABORT(__LINE__,__FILE__);
}
sprintf(linebuf,"%s -man %s > %s",NROFF,manfile,catfile);
} else {
fprintf(stderr,"illegal file type for %s: file skipped\n",
manfile);
continue;
}
}
if (v_flag) printf("%s\n",linebuf);
if (!p_flag) system(linebuf);
} /* done looping over files */
closedir(manp);
} /* done looping over sections */
/* set up for the next component of MANPATH */
pathIndex++;
current_path = manpath_array[pathIndex];
}
}
int main (int argc, char **argv) {
char *path;
int i, result1, result2;
/* make sure Gno is running */
if (needsgno()==0) {
fprintf(stderr,"Requires Gno/ME\n");
return 1;
}
#ifdef STACK_CHECK
begin_stack_check();
#endif
/* initialization */
v_flag = V_flag = M_flag = m_flag = p_flag = err_flag = 0;
result1 = result2 = 0;
/* parse command line and check usage */
while((i = getopt(argc,argv,"M:m:pVv")) != EOF) {
switch(i) {
case 'M':
if (m_flag) err_flag++;
M_flag++;
path = optarg;
break;
case 'm':
if (M_flag) err_flag++;
m_flag++;
path = optarg;
break;
case 'p':
p_flag++;
v_flag++;
break;
case 'V':
V_flag++;
break;
case 'v':
v_flag++;
break;
default:
err_flag++;
}
}
if (err_flag || V_flag) {
fprintf(stderr,"%s version %s by Devin Reade\n",
basename(argv[0]),versionstr);
}
if (err_flag) {
fprintf(stderr,"Usage: %s [-pVv] [-M path] [-m path] [section ...]\n",
basename(argv[0]));
}
if (err_flag || V_flag) return 1;
/* translate selected "sections" into something more understandable */
for (i=optind; i<argc; i++) {
if (!strcmp(argv[i],"local")) argv[i] = "l";
if (!strcmp(argv[i],"new")) argv[i] = "n";
if (!strcmp(argv[i],"old")) argv[i] = "o";
if (!strcmp(argv[i],"public")) argv[i] = "p";
}
/* do the search */
if (M_flag) {
manpath = path;
} else {
manpath = getManpath();
}
result1 = catman(argc-optind, &argv[optind]);
if (!M_flag) free(manpath);
if (m_flag) {
manpath = path;
result2 = catman(argc-optind, &argv[optind]);
}
#ifdef STACK_CHECK
fprintf(stderr,"stack usage: %d bytes\n",end_stack_check());
#endif
return (result1 || result2);
}

View File

@ -1,29 +0,0 @@
/*
* Copyright 1995 by Devin Reade <gdr@myrias.com>. For distribution
* information see the README file that is part of the manpack archive,
* or contact the author, above.
*/
segment "common____";
#include <types.h>
#include <string.h>
#include "man.h"
/*
* getSuffixIndex
*
* return the index into compressArray of the appropriate
* suffix/decompresser. If there is no match, return -1.
*/
int getSuffixIndex(char *name) {
char *p;
int i;
for (i=0; compressArray[i].suffix != NULL; i++) {
p = strstr(name,compressArray[i].suffix);
if (p && !*(p + strlen(compressArray[i].suffix))) return i;
}
return -1;
}

View File

@ -1,50 +0,0 @@
Name: apropos
Version: 3.0 (24 Jul 95)
Author: Devin Reade.
Contact: gdr@myrias.com
Where: /usr/bin
FTP: ftp.cco.caltech.edu, grind.isca.uiowa.edu
Locate commands by keyword. Bundled with catman, makewhatis,
man, and whatis in the manpack30.shk archive.
Name: catman
Version: 1.0 (24 Jul 95)
Author: Devin Reade.
Contact: gdr@myrias.com
Where: /usr/sbin
FTP: ftp.cco.caltech.edu, grind.isca.uiowa.edu
Preformat manual reference pages. Bundled with apropos, makewhatis,
man, and whatis in the manpack30.shk archive.
Name: makewhatis
Version: 1.2 (24 Jul 95)
Author: Devin Reade.
Contact: gdr@myrias.com
Where: /usr/sbin
FTP: ftp.cco.caltech.edu, grind.isca.uiowa.edu
Create the whatis database used by man(1), apropos(1), and whatis(1).
Bundled with apropos, catman, man, and whatis in the manpack30.shk archive.
Name: man
Version: 3.0 (24 Jul 95)
Author: Devin Reade.
Contact: gdr@myrias.com
Where: /usr/bin
FTP: ftp.cco.caltech.edu, grind.isca.uiowa.edu
Display manual reference pages. Bundled with apropos, catman,
makewhatis, and whatis in the manpack30.shk archive.
Name: whatis
Version: 3.0 (24 Jul 95)
Author: Devin Reade.
Contact: gdr@myrias.com
Where: /usr/bin
FTP: ftp.cco.caltech.edu, grind.isca.uiowa.edu
Locate commands by name. Bundled with apropos, catman,
makewhatis, and man in the manpack30.shk archive.

View File

@ -1,470 +0,0 @@
/*
* Copyright 1995 by Devin Reade <gdr@myrias.com>. For distribution
* information see the README file that is part of the manpack archive,
* or contact the author, above.
*/
segment "makewhatis";
#include <stdio.h>
#include <string.h>
#include <ctype.h>
#include "makewhatis.h"
#define NAME1 "NAME"
#define NAME2 "N\bNA\bAM\bME\bE"
#define NAME3 "N\bN\bN\bNA\bA\bA\bAM\bM\bM\bME\bE\bE\bE"
#define SYNOPSIS1 "SYNOPSIS"
#define SYNOPSIS2 "S\bSY\bYN\bNO\bOP\bPS\bSI\bIS\bS"
#define SYNOPSIS3 "S\bS\bS\bSY\bY\bY\bYN\bN\bN\bNO\bO\bO\bOP\bP\bP\bPS\bS\bS\bSI\bI\bI\bIS\bS\bS\bS"
#define DESCRIPTION1 "DESCRIPTION"
#define DESCRIPTION2 "D\bDE\bES\bSC\bCR\bRI\bIP\bPT\bTI\bIO\bON\bN"
#define DESCRIPTION3 "D\bD\bD\bDE\bE\bE\bES\bS\bS\bSC\bC\bC\bCR\bR\bR\bRI\bI\bI\bIP\bP\bP\bPT\bT\bT\bTI\bI\bI\bIO\bO\bO\bON\bN\bN\bN"
char buffer[BUFFERSIZE]; /* contains the command description */
char titlebuf[BUFFERSIZE]; /* contains the command name */
static char buffer2[BUFFERSIZE]; /* used for chars read from man page */
#ifdef TEST_FILLBUFFER
short v_flag=2;
# define output_fp stdout
# define error_fp stderr
#else
extern FILE *output_fp; /* output file descriptor -- may be stdout */
extern FILE *error_fp; /* error file descriptor -- may be stderr */
#endif
/* void fillbuffer (char *filename);
*
* Pre: <filename> is the name of the man page or temporary file
* containing text. It may have nroff formatting information
* or screen control codes, but must not be either a compressed
* file nor an AWGS word processor file.
*
* Post: <buffer> will contain all the text, minus formatting and control
* code, starting from the word "NAME" and ending with either ".SH".
* "SYNOPSIS", or "DESCRIPTION", whichever comes first. <titlebuf>
* will contain all printable text starting with the first printable
* non-whitespace character following "NAME" and ending with the
* last printable character before the first '-' following "NAME".
*
* If an error occurs, <buffer> will be an empty string (ie:
* buffer[0] == '\0')
*
* Warning: This routine was written to be fast at the expense of code
* size. It also has a lot of "special case"ing since it could
* be fed nroff source, aroff'd output, or text files that may
* include formatting control codes. If you're looking for some
* nice neat code, you're not going to find it here.
*/
void fillbuffer (char *filename) {
FILE *fp; /* FILE pointer for filename */
int count; /* how many chars were read into buffer2 */
char *p1; /* points to current char in buffer2 */
char *p2; /* points to last char (of interest) in buffer2 */
char *p3; /* points to current char in buffer */
char *p6; /* scratch */
short found; /* some flags */
short in_comment;
short in_format_BR;
short in_format_f;
short foo;
/*
* Set p4 and p5 to the ends of buffer and titlebuf, respectively.
* These are used for error checking, so that we don't overflow the
* buffers. Using pointers will speed things up a bit at the cost
* of four bytes of local storage. They are not global for the sake
* of speed.
*/
char *p4 = buffer + BUFFERSIZE;
char *p5 = titlebuf + BUFFERSIZE;
/*
* open the file
*/
if ((fp = fopen(filename,"rb")) == NULL) {
buffer[0] = '\0';
if (v_flag) fprintf (error_fp,"Open failed for file \"%s\"\n",filename);
return;
}
/*
* see if it includes another man page
*/
if ((fgets(buffer2,4,fp) == NULL) || (strncmp(buffer2,".so",3)==0)) {
buffer[0] = '\0';
titlebuf[0] = '\0';
fclose(fp);
return;
}
fseek(fp,0L,SEEK_SET);
/*
* Make fp point to the first newline following NAME so that the
* next block read will pick it up as the first character. This is
* needed for the next section of code following this one.
*/
for(;;) {
/*
* read in buffer2 in a line-oriented fashion at first so that we
* can more easily ignore .\" and .TH lines
*/
if (fgets(buffer2,BUFFERSIZE,fp)==NULL) {
/*
* eof or error, and we haven't found "NAME" yet ... return
* an empty string
*/
buffer[0] = '\0';
titlebuf[0] = '\0';
fclose(fp);
if (v_flag) fprintf (error_fp,
"EOF or error on %s, NAME not found.\n",filename);
return;
}
/* ignore comment lines and any .TH line(s) */
if ((strncmp(buffer2,".\\\"",3)==0) || (strncmp(buffer2,".TH",3)==0))
continue;
/* check the various versions of "NAME" */
if (strstr(buffer2,NAME1) != NULL) break;
if (strstr(buffer2,NAME2) != NULL) break;
if (strstr(buffer2,NAME3) != NULL) break;
}
/* we need the previous newline for the next algorithm to work */
fseek(fp,-1L,SEEK_CUR);
/*
* Make p1 point to spot in buffer2 where there occurs the first
* character following '-' which in turn follows "NAME".
* Note that if "NAME" or '-' are within a comment line
* (nroff source), it will still be picked up.
*
* Also copy selected chars to titlebuf until the first '-' is found.
*/
p3 = titlebuf;
found = 0; /* set this when we find '-' */
in_format_BR = 0; /* in the middle of a .BR format */
in_format_f = 0; /* in the middle of a \fI format */
in_comment = 0; /* in the middle of a .\" comment */
foo = 0; /* haven't found the printable character after NAME */
for(;;) {
/* read another block into buffer2. */
count = fread(buffer2,sizeof(char),BUFFERSIZE-1,fp);
if (count == 0) {
/* eof or error; empty buffer and titlebuf then return */
buffer[0] = '\0';
titlebuf[0] = '\0';
fclose(fp);
if (v_flag) fprintf (error_fp,
"EOF or error on %s, command name not found.\n",filename);
return;
}
buffer2[count] = '\0';
p1 = buffer2;
/* mark the "end" of buffer2 with p2 */
if ((p2 = strchr(p1,'-')) != NULL) {
found = 1;
} else {
p2 = buffer + count;
}
/*
* If this is not our first iteration, dump any formatting information
* or comments left over from the last interation.
*/
if (in_comment) {
while((p1<p2) && (*p1 != '\r')) p1++;
in_comment = 0;
}
if (in_format_BR) {
while ((p1<p2) && !isspace(*p1)) p1++;
in_format_BR = 0;
}
if (in_format_f) {
p1 = p1 + 3 - in_format_f;
in_format_f = 0;
}
/*
* At this time, p1 points to the start of the key words, p2
* to either the end of the key words or the end of buffer2,
* and p3 into the spot in titlebuf where the next character should
* be put.
*
* Copy *p1 to *p3 while p1<p2 (not at end of titlebuf or key words),
* skipping comments, formatting info, and control chars
*/
for (; p1<p2; p1++) {
/* skip .\" comments */
if (strncmp(p1,"\r.\\\"",4) == 0) {
while ((p1<p2) && (*p1!='\r')) p1++;
if (p1==p2) in_comment = 1;
continue;
}
/* skip .BR-type formatting */
if ((p1<p2) && (*p1=='\r') && (*(p1+1)=='.')) {
p1++;
while ((p1<p2) && !isspace(*p1)) p1++;
if (p1==p2) in_format_BR = 1;
else --p1;
continue;
}
/* skip \fI-type formatting */
if ((p1<p2) && (*p1=='\\') && (*(p1+1)=='f')) {
if ((p1 + 3) < p2) {
p1 += 3;
} else {
in_format_f = p2 - p1;
p1 = p2;
}
continue;
}
/*
* skip whitespace if we haven't got the beginning of the
* description yet.
*/
#ifdef ISGRAPH_FIX
if (isgraph(*p1) && (*p1!=' ')) foo=1;
if (!foo) {
while ((p1<p2) && !(isgraph(*p1) && (*p1!=' '))) p1++;
if ((*p1=='.') && (*(p1-1)=='\r')) p1 -=2;
else --p1;
continue;
}
#else
if (isgraph(*p1)) foo=1;
if (!foo) {
while ((p1<p2) && !isgraph(*p1)) p1++;
if ((*p1=='.') && (*(p1-1)=='\r')) p1 -=2;
else --p1;
continue;
}
#endif
/*
* at this point, *p1 is either a control char or something that
* we want in titlebuf, assuming that p1<p2.
*/
if ((p1<p2) && !iscntrl(*p1)) {
/*
* The conditional below means:
* Copy it so that: 1. There is only one space between words; and
* 2. The buffer doesn't begin with a space.
*/
if ( !((p3>titlebuf) && (*p1 == ' ') && (*(p3-1) == ' ')) &&
!((p3==titlebuf) && (*p3 == ' '))
) {
/* don't let a space precede a comma */
if ((*p1==',') && (*(p3-1)==' ')) {
*(p3-1) = ',';
continue;
} else *p3++ = *p1;
if (p3>=p5) { /* titlebuf overflow? */
if (v_flag)
fprintf(error_fp,"command name buffer overflow on %s\n",
filename);
buffer[0] = '\0';
titlebuf[0] = '\0';
fclose(fp);
return;
}
}
}
}
if (found) { /* we've got all of the key words */
p3--; /* p3 now points to last char, not terminator */
if (*p3=='\\') p3--;
while(isspace(*p3)) p3--;
*(p3+1) = '\0';
break;
}
}
p1 = p2 + 1;
#ifdef ISGRAPH_FIX
while ( (p1 < buffer2 + BUFFERSIZE) &&!(isgraph(*p1) && (*p1 != ' '))) p1++;
#else
while ((p1 < buffer2 + BUFFERSIZE) && !isgraph(*p1)) p1++;
#endif
/*
* now copy selected chars to buffer until the next subheading is found
*/
p3 = buffer;
found = 0; /* set this when we find one of the above strings */
in_format_BR = 0; /* in the middle of a .BR format */
in_format_f = 0; /* in the middle of a \fI format */
in_comment = 0; /* in the middle of a .\" comment */
for(;;) {
/* mark the "end" of buffer2 with p2 */
if ( ((p2 = strstr(p1,".SH")) != NULL) ||
((p2 = strstr(p1,SYNOPSIS1)) != NULL) ||
((p2 = strstr(p1,SYNOPSIS2)) != NULL) ||
((p2 = strstr(p1,SYNOPSIS3)) != NULL) ||
((p2 = strstr(p1,DESCRIPTION1)) != NULL) ||
((p2 = strstr(p1,DESCRIPTION2)) != NULL) ||
((p2 = strstr(p1,DESCRIPTION3)) != NULL)
) {
*p2 = '\0';
/*
* this conditional is to cover the wierd case of having the word
* "SYNOPSIS" appearing in the description (or elsewhere), as
* it does for the GNO Intro(1) man page. Blech. Only in
* aroff source or a preformatted page would this matter.
*/
if (((p6 = strstr(p1,SYNOPSIS1)) != NULL) ||
((p6 = strstr(p1,DESCRIPTION1)) != NULL)) {
p2 = p6;
}
found = 1;
} else {
p2 = buffer + count;
}
/*
* If this is not our first iteration, dump any formatting information
* or comments left over from the last interation.
*/
if (in_comment) {
while((p1<p2) && (*p1 != '\r')) p1++;
in_comment = 0;
}
if (in_format_BR) {
while ((p1<p2) && !isspace(*p1)) p1++;
in_format_BR = 0;
}
if (in_format_f) {
p1 = p1 + 3 - in_format_f;
in_format_f = 0;
}
/*
* At this time, p1 points to the start of the description, p2
* to either the end of the description or the end of buffer2,
* and p3 into the spot in buffer where the next character should
* be put.
*
* Copy *p1 to *p3 while p1<p2 (not at end of buffer or description),
* skipping comments, formatting info, and control chars
*/
for (; p1<p2; p1++) {
/* skip .\" comments */
if (strncmp(p1,"\r.\\\"",4) == 0) {
while ((p1<p2) && (*p1!='\r')) p1++;
if (p1==p2) in_comment = 1;
}
/* skip .BR-type formatting */
if ((p1<p2) && (*p1=='\r') && (*(p1+1)=='.')) {
p1++;
while ((p1<p2) && !isspace(*p1)) p1++;
if (p1==p2) in_format_BR = 1;
}
/* skip \fI-type formatting */
if ((p1<p2) && (*p1=='\\') && (*(p1+1)=='f')) {
if ((p1 + 3) < p2) {
p1 += 3;
} else {
in_format_f = p2 - p1;
p1 = p2;
}
}
/*
* at this point, *p1 is either a control char or something that
* we want in buffer, assuming that p1<p2.
*/
if ((p1<p2) && !iscntrl(*p1)) {
/*
* The conditional below means:
* Copy it so that: 1. There is only one space between words; and
* 2. The buffer doesn't begin with a space.
*/
if ( !((p3>buffer) && (*p1 == ' ') && (*(p3-1) == ' ')) &&
!((p3==buffer) && (*p3 == ' '))
) {
*p3++ = *p1;
if (p3>=p4) { /* buffer overflow? */
if (v_flag)
fprintf(error_fp,"command description buffer overflow on %s\n",
filename);
buffer[0] = '\0';
titlebuf[0] = '\0';
fclose(fp);
return;
}
}
}
}
if (found) { /* we've got the entire description */
*p3 = '\0';
break;
}
/*
* We're part way through the description; read another block
* into buffer2.
*/
count = fread(buffer2,sizeof(char),BUFFERSIZE-1,fp);
if (count == 0) {
/* eof or error; terminate buffer and return */
*p3 = '\0';
fclose(fp);
if (v_flag) fprintf (error_fp,
"EOF or error on %s, description not found.\n",filename);
return;
}
buffer2[count] = '\0';
p1 = buffer2;
}
/*
* close the file
*/
fclose(fp);
return;
}

View File

@ -1,42 +0,0 @@
/*
* Copyright 1995 by Devin Reade <gdr@myrias.com>. For distribution
* information see the README file that is part of the manpack archive,
* or contact the author, above.
*/
#include <types.h>
#include "man.h"
/*
* The compression suffixes and how to uncompress the files.
* If you use ".l" (that's "ell") as a suffix, you will break the
* algorithm for dereferencing aroff "links".
*/
compressionType compressArray[] = {
{ ".Z", "compress -cd" },
{ ".F", "freeze -cd" },
{ ".gz", "gzip -cd" },
{ NULL, NULL }
};
char linebuf[BUFFERSIZE];
char linebuf2[BUFFERSIZE];
char *manpath;
Section sections[] = {
{ "1", "1" },
{ "2", "2" },
{ "3", "3" },
{ "3f", "3f" },
{ "4", "4" },
{ "5", "5" },
{ "6", "6" },
{ "7", "7" },
{ "8", "8" },
{ "new", "n" }, /* the words "new", "local", "public", */
{ "local", "l" }, /* and "old" can be abbreviated on the */
{ "public", "p" }, /* command line with "n", "l", "p", and */
{ "old", "o" }, /* "o", respectively */
{ NULL, NULL } /* MUST be NULL-terminated! */
};

View File

@ -1,70 +0,0 @@
#
# Makefile for the man package, for use with dmake(1).
#
# Location for executables. They should normally be /usr/sbin and /usr/bin.
SBINDIR = /usr/sbin
BINDIR = /usr/bin
# Location for man pages. Usually /usr/man.
MANDIR = /usr/man
#
# You should not have to change anything below this line
#
# Define: -DDEBUG to produce more debugging info and checks
#
# -DSTACK_CHECK to show stack usage. If you use this
# one, ensure you add -l/usr/lib/stack to your LDLIBS.
#
STACK = -s1270
DEFINES =
CFLAGS = $(DEFINES) $(STACK) -w -v -O -I/usr/include
LDFLAGS = -v
LDLIBS = -l/usr/lib/gnulib -l/usr/lib/stack
CP = /bin/cp -f
build: apropos catman makewhatis man whatis
apropos: apropos.o apropos2.o util.o utilgs.o globals.o
$(CC) $(LDFLAGS) $< $(LDLIBS) -o $@
catman: catman.o util.o utilgs.o globals.o common.o
$(CC) $(LDFLAGS) $< $(LDLIBS) -o $@
makewhatis: makewhatis.o fillbuffer.o process.o
$(CC) $(LDFLAGS) $< $(LDLIBS) -o $@
man: man.o man2.o apropos2.o util.o utilgs.o globals.o common.o
$(CC) $(LDFLAGS) $< $(LDLIBS) -o $@
whatis: whatis.o apropos2.o util.o utilgs.o globals.o
$(CC) $(LDFLAGS) $< $(LDLIBS) -o $@
clobber:
$(RM) *.o *.root
install:
$(CP) apropos man whatis $(BINDIR)
$(CP) catman makewhatis $(SBINDIR)
$(CP) apropos.1 man.1 whatis.1 $(MANDIR)/man1
$(CP) catman.8 makewhatis.8 $(MANDIR)/man8
# additional dependancies
apropos.o:: man.h util.h
apropos2.o:: man.h util.h
catman.o:: man.h util.h
common.o:: man.h util.h
fillbuffer.o:: makewhatis.h
globals.o:: man.h
makewhatis.o:: makewhatis.h
man.o:: man.h util.h
man2.o:: man.h util.h
process.o:: makewhatis.h
util.o:: util.h
utilgs.o:: util.h
whatis.o:: man.h util.h

View File

@ -1,303 +0,0 @@
.TH MAKEWHATIS 8 "System Administration" "24 July 1995" "Version 1.2"
.SH NAME
.B makewhatis
\- generate the whatis database file
.SH SYNOPSIS
.B makewhatis
[
.B -c
|
.B -C
] [
.BI -f " outfile"
] [
.BI -l " logfile"
] [
.BI -o " dbfile"
] [
.BI -p " path"
] [
.BI -v " n"
] [
.B -V
]
.SH DESCRIPTION
.B makewhatis
generates the whatis database for
.BR apropos (1),
.BR man (1),
and
.BR whatis (1).
This database is a text file containing line oriented records. Each record
contains a man page name, the section number, and the brief description.
.LP
.B Makewhatis
makes use of one of the environment variables
.BR MANPATH ,
.BR USRMAN ,
or
.BR MANDIR ,
in the listed order of preference. It will use this
environment variable to determine for which manual pages the whatis
database should be built. If the environment variable contains more than
one path (delimited by either colons or spaces),
then whatis databases will be generated
in all of the specified paths. This may be overridden by the
.BR -p
flag.
.LP
By default,
.BR makewhatis
will generate its database from manual pages existing in the
.IB manpath_component /man X
subdirectories (where
.I X
is the section number)
that are either
.BR aroff
or
.BR nroff
source files.
However, since many GNO programmers are providing only preformatted
text versions of their man pages, using the
.I -c
flag will cause
.B makewhatis
to also use manual pages in the
.IB manpath_component /cat X
subdirectories when building the database.
If there is a corresponding manual page in both the
.BI man X
and
.BI cat X
subdirectory, then only the page in the
.BI man X
subdirectory will be used.
.LP
Manual pages which are
.BR nroff
source files in the
.BI man X
subdirectory, or are preformatted text in the
.BI cat X
subdirectory may be compressed by either
.BR compress (1),
.BR freeze (1),
or
.BR gzip (1),
provided that the suffixes on the compressed file are
.BR ".Z" ,
.BR ".F" ,
and
.BR ".gz" ,
respectively. The case of the suffix is significant.
.BR Aroff
source files
.I "must not"
be compressed by any method.
.LP
All
.BR aroff
link files are ignored. A file is assumed to be an
.BR aroff
link file if it ends in
.B ".l"
(dot lower-case ell) and is not within a
.BR manl
(man-ell) or a
.BR catl
(cat-ell) subdirectory.
.LP
Note that the lines in the whatis database file are created in the order
that the man pages are found. It is suggested that the database files
be sorted after
.B makewhatis
is finished. See
.BR sort (1)
or
.BR msort (1) .
.SH OPTIONS
.IP "\fB\-c\fP"
will check
.BI cat X
subdirectories as well as
.BI man X
subdirectories.
.IP \fB\-C\fP
will check
.I only
.BI cat X
subdirectories,
.I not
.BI man X
subdirectories.
.IP "\fB-f\fR \fIoutfile\fR"
causes the
.B makewhatis
status output to be placed in
.IR outfile .
Invoking
.B -f
without
.B -v2
produces no output.
.IP "\fB-l\fR \fIlogfile\fR"
will cause any error messages to be printed to
.IR logfile .
Invoking
.B -l
without either
.B -v1
or
.B -v2
produces no output.
.IP "\fB-o\fR \fIdbfile\fR"
will make
.B makewhatis
use
.I dbfile
as the name for the generated whatis databases. While it is possible to
use a full pathname for
.IR dbfile ,
this will result in that file being overwritten for each colon- or
space-delimited entry in
.BR MANPATH .
.IP "\fB-p\fR \fIpath\fR"
overrides the environment variables
.B MANPATH
et al for determining for which manual page hierarchies the databases must
be generated.
.IP "\fB-v\fR \fIn\fR"
creates verbose status messages during execution. For
.IR n =1
only major error messages are printed out. For
.IR n =2,
the names of processed files are also printed. For
.IR n =3,
the output becomes very verbose with excessive status information, including
listing any missing subdirectores.
.IP \fB-V\fR
will show version and usage information, then exit.
.SH ENVIRONMENT
.BR MANPATH
.br
.BR USRMAN
.br
.BR MANDIR
.RS
Unless the
.B -p
flag is used,
.B makewhatis
will use the first that it finds of these environment variables for
determining where database files should be generated. The search
is done in the order shown. While
.B makewhatis
will correctly handle
.RB ` ~ '
and
.RB ` . '
being part of these paths, it will not correctly handle
.RB ` .. '.
.sp 1
Either colons or spaces can be used to delimit the individual paths.
If the value of the selected environment variable contains no spaces
nor
.B /
characters (such as
.BR :usr:local:man ),
it is assumed to be a single path, not a list of paths.
.sp 1
Although
.B makewhatis
allows
.BR USRMAN
and
.BR MANDIR
to be each a colon- or space-separated list of pathnames,
it is recommended that for compatibility with
.BR man
(version 2.1 and earlier) these variables, if used, should be
a single pathname.
.RE
.SH CAVEATS
.B Makewhatis
assumes that the programs
.BR aroff ,
.BR compress ,
.BR freeze ,
and
.BR gzip
are available to the executing shell via the
.BR system (2)
call.
.BR Nroff
is not used and need not be available.
.LP
Because
.B makewhatis
looks for the string
.B NAME
and one of
.BR .SH ,
.BR SYNOPSIS ,
or
.B DESCRIPTION
when processing files, it can be confused by missing fields or
some methods of formatting. For example, if in a preformatted manual page
.B NAME
is underlined by repeated backspace-_ sequences, then the generated
description for that particular man page is unpredictable,
though usually blank. When parsing preformatted manual pages,
.B makewhatis
will understand the common double- and quadruple-boldfaced
subheadings, provided
that the backspace character (control-H) is used to achieve this effect.
.LP
Similarily,
.B makewhatis
expects the subheading
.B NAME
to be in the format:
.nf
NAME
\fIcommand_name\fR [...] - \fIbrief description\fR
.fi
If this is not so (ignoring whitespace), then the output is unpredictable.
.LP
Man pages must be CR-delimited (ASCII 015, or control\-M).
.LP
Where unpredictable output has been mentioned above, this means that
the description in the database file will either be blank or random
text from the man page. It
.I "does not"
mean that system integrity or that the remainder of the database file
has been affected.
.LP
Any text appearing after
.B NAME
on the NAME header line will be ignored.
.SH BUGS
.B Makewhatis
reads files in blocks of 1024 characters.
If formatting information is split by the end
of the input buffer, you may see formatting infomation such as
.B .BR
in the output. This was not fixed due to the overhead of having to
check for such a condition.
.LP
Please report any additional bugs to Devin Reade, <gdr@myrias.com>.
.SH FILES
.nf
/usr/[share/]man/whatis -- the whatis database
.fi
.SH SEE ALSO
.BR apropos (1),
.BR aroff (1),
.BR catman (1),
.BR compress (1),
.BR freeze (1),
.BR gzip (1),
.BR man (1),
.BR nroff (1),
.BR whatis (1)

View File

@ -1,334 +0,0 @@
/*
* Copyright 1995 by Devin Reade <gdr@myrias.com>. For distribution
* information see the README file that is part of the manpack archive,
* or contact the author, above.
*/
segment "makewhatis";
#include <sys/types.h>
#include <stdio.h>
#include <stdlib.h>
#include <errno.h>
#include <string.h>
#include <dirent.h>
#include <unistd.h>
#include "getopt.h"
#include <libc.h>
#include "makewhatis.h"
#ifdef STACK_CHECK
extern void begin_stack_check(void);
extern int end_stack_check(void);
#endif
/*
* Options:
*
* -c check cat* subdirectories as well
* -C check _only_ cat* subdirectories, not man* subdirectories.
* -f outfile force whatis status output to <outfile>
* -l logfile log errors to <logfile>
* -o dbfile force whatis database output to <dbfile>
* -p path use the <path> rather than $MANPATH, $USRMAN, or $MANDIR
* -s sort the whatis database by manual page name
* -v{1|2|3} verbose
* -V show version and usage info and exit
*/
char *man_subdir[] = {
"man1",
"man2",
"man3",
"man3f",
"man4",
"man5",
"man6",
"man7",
"man8",
"mann",
"manl",
"manp",
"mano",
NULL
};
/*
* we include cat* since some Gno utility man pages aren't written in
* either nroff or aroff source ... go figure.
*/
char *cat_subdir[] = {
"cat1",
"cat2",
"cat3f",
"cat4",
"cat5",
"cat6",
"cat7",
"cat8",
"catn",
"catl",
"catp",
"cato",
NULL /* _must_ be NULL terminated! */
};
/* For the various command line flags */
short c_flag = 0;
short C_flag = 0;
short o_flag = 0;
short p_flag = 0;
short v_flag = 0;
short errflag = 0; /* This is set if there is a usage error or -V flag */
static char filebuffer[FILENAME_MAX]; /* used when traversing cat* pages */
static char progdir[FILENAME_MAX]; /* the directory where makewhatis started */
FILE *output_fp;
FILE *error_fp;
int main (int argc, char **argv) {
char *manpath; /* the location of the man pages */
char *path; /* the current path; taken from manpath */
char *p=NULL; /* a temporary pointer */
struct dirent *file; /* the current file we have open */
char tmp_file[L_tmpnam]; /* a scratch file */
FILE *tmp_fp; /* pointer to tmp_file */
FILE *whatis_fp; /* pointer to the current whatis database */
DIR *subdir; /* the current man subdirectory -- eg: /usr/man/man3 */
char *dbfile; /* non-default name of the whatis database */
char *dirsep; /* the directory separator, either "/" or ":" */
int i;
extern int optind;
extern char *optarg;
/* make sure Gno is running */
if (needsgno()==0) {
fprintf(stderr,"Requires Gno/ME\n");
return 1;
}
#ifdef STACK_CHECK
begin_stack_check();
#endif
/*
* set the defaults
*/
output_fp = stdout;
error_fp = stderr;
if (getwd(progdir) == NULL) {
perror("getwd() failed");
exit(1);
}
/*
* parse the command line
*/
while((i = getopt(argc,argv,"cCf:l:o:p:v:V")) != EOF)
switch(i) {
case 'c':
if (C_flag) errflag++;
else c_flag++;
break;
case 'C':
if (c_flag) errflag++;
else C_flag++;
break;
case 'f':
output_fp = fopen (optarg,"w");
if (output_fp == NULL) {
fprintf(stderr,"Could not open output file %s; using stdout.\n",
optarg);
output_fp = stdout;
}
break;
case 'l':
error_fp = fopen (optarg,"w");
if (error_fp == NULL) {
fprintf(stderr,"Could not open log file %s; using stderr.\n",
optarg);
error_fp = stderr;
}
break;
case 'o':
o_flag++;
dbfile = optarg;
break;
case 'p':
p_flag++;
p = optarg;
break;
case 'v':
v_flag = (short) atoi(optarg);
if ((v_flag<1) && (v_flag>3)) errflag++;
break;
case 'V':
fprintf(stderr,
"%s --\n\tCreate the %s database.\n\tVersion %s by Devin Reade\n\n",
argv[0],WHATIS,VERSIONSTRING);
errflag++;
break;
default:
errflag++;
break;
}
if (errflag) {
fprintf(error_fp,
"Usage:\n%s\t[-c|-C] [-f outfile] [-l logfile] [-o dbfile] [-p path]\n\
\t\t[-v 1|2] [-V]\n\n\
-c\t\tCheck catX subdirectories as well\n\
-C\t\tCheck _only_ catX subdirectories, not manX subdirectories.\n\
-f outfile\tForce whatis output to <outfile>.\n\
-l logfile\tLog errors to <logfile>.\n\
-o dbfile\tforce whatis database output to <dbfile>.\n\
-p path\t\tUse the <path> rather than $MANPATH, $USRMAN, or $MANDIR.\n\
-v n\t\t<n>=1: Slightly verbose, only displaying major errors.\n\
\t\t<n>=2: Verbose, displaying processed file names.\n\
\t\t<n>=3: Very verbose, displaying more processing info.\n\
-V\t\tShow version and usage information, then exit.\n",argv[0]);
return -1;
}
/*
* get the location of the man pages; p is already set if -p flag used
*/
if (p == NULL) p = getenv("MANPATH");
if (p == NULL) p = getenv("USRMAN");
if (p == NULL) p = getenv("MANDIR");
if (p == NULL) p = DEFAULT_MANPATH;
/* define the directory separator */
dirsep = (strchr(p,':')==NULL) ? "/" : ":";
/* make a copy of the location */
if ((manpath = malloc (strlen(p) + 1)) == NULL) {
if (v_flag) fprintf(error_fp,
"malloc failed while making copy of \"%s\"\nAborted.\n",p);
return -1;
}
strcpy(manpath,p);
/* get the name of the temporary file */
tmpnam (tmp_file);
/*
* loop over all the paths in manpath. Don't use ':' as a delimiter since
* the colon is a pathname separator under GS/OS.
*/
path = strtok (manpath," ");
while (path != NULL) {
if (access(path,F_OK)==0) {
if (strcmp(path,".") == 0) {
chdir(progdir);
} else {
chdir(path);
}
/* open the whatis database file */
if (!o_flag) dbfile = WHATIS;
whatis_fp = fopen(dbfile,"w");
if (whatis_fp == NULL) {
fprintf (error_fp,
"Could not create whatis database file %s in directory %s.\n\
Aborted.\n",
dbfile,path);
exit(-1);
}
/*
* loop over the expected man* subdirectories within path
*/
if (!C_flag) for (i=0; man_subdir[i] != NULL; i++) {
subdir = opendir(man_subdir[i]);
if (subdir != NULL) {
/* print status */
if (v_flag>=3) fprintf(output_fp,
"Now working on directory %s\t%s ...\n",path,man_subdir[i]);
/* no need to error check because of opendir() */
chdir(man_subdir[i]);
/* loop over files within subdirectory */
while ((file = readdir(subdir)) != NULL) {
process (file->d_name,tmp_file,whatis_fp,&man_subdir[i][3]);
}
closedir(subdir);
} else {
if (v_flag>=3) fprintf(output_fp,
"Could not access files in %s\t%s ...\n",path,man_subdir[i]);
}
chdir(path);
}
/*
* loop over the expected cat* subdirectories within path,
* adding only those files without man* versions.
*/
if (c_flag||C_flag) for (i=0; cat_subdir[i] != NULL; i++) {
subdir = opendir(cat_subdir[i]);
if (subdir != NULL) {
/* print status */
if (v_flag>=3) fprintf(output_fp,
"Now working on directory %s\t%s ...\n",path,cat_subdir[i]);
/* no need to error check because of opendir() */
chdir(cat_subdir[i]);
/* make filebuffer contain path to matching man* subdirectory */
strcpy(filebuffer,path);
strcat(filebuffer,dirsep);
strcat(filebuffer,man_subdir[i]);
strcat(filebuffer,dirsep);
p = filebuffer + strlen(filebuffer); /* p points to '\0' */
/* loop over files that don't have a man* counterpart */
while ((file = readdir(subdir)) != NULL) {
strcpy(p,file->d_name);
if (access(filebuffer,F_OK)!=0)
process (file->d_name,tmp_file,whatis_fp,
&man_subdir[i][3]);
}
closedir(subdir);
} else {
if (v_flag>=3) fprintf(output_fp,
"Could not access files in %s\t%s ...\n",path,cat_subdir[i]);
}
chdir(path);
}
/* close the database */
fclose(whatis_fp);
}
/* get the next path in manpath */
path = strtok (NULL," ");
}
/* clean up and exit */
unlink(tmp_file);
if (output_fp != stdout) fclose(output_fp);
if (error_fp != stderr) fclose(error_fp);
#ifdef STACK_CHECK
fprintf(stderr,"Makewhatis stack usage: %d bytes\n",end_stack_check());
#endif
return 0;
}

View File

@ -1,27 +0,0 @@
/*
* Copyright 1995 by Devin Reade <gdr@myrias.com>. For distribution
* information see the README file that is part of the manpack archive,
* or contact the author, above.
*/
#define VERSIONSTRING "1.2"
#define ISGRAPH_FIX 1
/* The size of the IO buffers */
#define BUFFERSIZE 1024
/* The default name for the whatis database */
#define WHATIS "whatis"
/* The number of characters per tab in the whatis database */
#define TABLENGTH 8
#define DEFAULT_MANPATH "/usr/man"
extern int chdir (const char *);
extern int system (const char *);
void fillbuffer (char *filename);
void process (char *filename, char *tmp_file, FILE *whatis_fp, char *sec);
extern short v_flag;

View File

@ -1,519 +0,0 @@
.\" This man page copyright (c) 1980 Regents of the University of California.
.\" All rights reserved. The Berkeley software License Agreement
.\" specifies the terms and conditions for redistribution.
.\"
.\" While this manual page is based on one from UCB, the included
.\" C source, makefile, and executables are copyright (c) 1995
.\" by Devin Reade <gdr@myrias.com>. All rights reserved.
.\"
.TH MAN 1 "Commands and Applications" "24 July 95" "Version 3.0"
.SH NAME
man \- display reference manual pages; find reference pages by keyword
.SH SYNOPSIS
.B man
.RB "[\|" \- "\|]"
.RB "[\|" \-t "\|]"
.RB "[\|" \-M
.IR path "\|]"
.RB "[\|" \-T
.IR macro-package "\|]"
.RI "[\|" section "\|] " title "
.br
.B man
.RB "[\|" \-M
.IR path "\|]"
.B \-k
.I keyword
\&.\|.\|.
.br
.B man
.RB "[\|" \-M
.IR path "\|]"
.B \-f
.I filename
\&.\|.\|.
.SH DESCRIPTION
.B man
displays information from the reference manuals.
It can display complete manual pages that you select by
.IR title ,
or one-line summaries selected either by
.I keyword
.RB ( \-k ),
or by the name of an associated file
.RB ( \-f ).
.LP
A
.IR section ,
when given, applies to the
.I title
that follows it on the command line.
.B man
looks in the indicated section of the manual for that
.IR title .
.I section
is either a digit (perhaps followed by a single letter indicating
the type of manual page), or one of the words
.BR new ,
.BR local ,
.BR old ,
or
.BR public .
The
abbreviations
.BR n ,
.BR l ,
.B o
and
.B p
are also allowed.
If
.I section
is omitted,
.B man
searches all reference sections
(giving preference to commands over functions).
If more than one manual page exists for the specified
.IR title ,
each page is displayed in the order in which it is found. The
user is given the option of exiting after each page is displayed.
If no manual page is located,
.B man
prints an error message.
.LP
The reference page sources are typically located in the
.BR /usr/man/man?
directories.
If there are preformatted, up-to-date versions in
corresponding
.B cat?
or
.B fmt?
directories,
.B man
simply displays or prints those versions.
If the preformatted
version of interest is out of date or missing,
.B man
reformats it prior to display.
If directories for the
preformatted versions are not provided,
.B man
reformats a page whenever it is requested.
.LP
If the standard output is not a terminal, or if the
.RB ` \- '
flag is given,
.B man
pipes its output through
.BR cat (1V).
Otherwise,
.B man
pipes its output through
.BR more (1)
to handle paging and underlining on the screen.
.SH OPTIONS
.IP \fB\-t\fP
.B man
arranges for the specified manual pages to be
.BR troff ed
to a suitable raster output device (see
.BR troff (1)
or
.BR vtroff (1)).
If both the
.B \-
and
.B \-t
flags are given,
.B man
updates the
.BR troff ed
versions of each named
.I title
(if necessary), but does not display them.
.IP "\fB\-M\fP \fIpath\fP"
Change the search path for manual pages.
.I path
is a colon- or space-separated list of directories that contain manual page
directory subtrees.
For example,
.B /usr/man/u_man:/usr/man/a_man
makes
.B man
search in the standard System V locations.
The space delimiter is provided for compatibility with GS/OS's
use of the colon as a pathname component delimiter. If the search
path contains no spaces nor
.B /
characters (such as
.BR :usr:local:man ),
it is assumed to be a single path, not a list of paths.
If spaces are used as delimiters, remember to quote
.I path
from the shell.
Each directory in the
.I path
is assumed to contain subdirectories of the form
.BR man[1-8l-p] .
.IP "\fB\-T\fP \fImacro-package\fP"
.B man
uses
.I macro-package
rather than the standard
.B \-man
macros defined in
.B /usr/lib/tmac/tmac.an
for formatting manual pages.
.IP "\fB\-k\fP \fIkeyword .\|.\|.\fP"
.B man
prints out one-line summaries from the
.B whatis
database (table of contents) that contain any of the given
.IR keyword s.
The
.B whatis
database is created using the
.BR makewhatis (8)
command.
.IP "\fB\-f\fP \fIfilename .\|.\|.\fP"
.B man
attempts to locate manual pages related to any of the given
.IR filename s.
It strips the leading pathname components from each
.IR filename ,
and then prints one-line summaries containing the resulting
basename or names.
This option also uses the
.B whatis
database.
.br
.ne 7
.SH "MANUAL PAGES"
.LP
Manual pages are either
.BR nroff (1)/ troff (1)
source files prepared with the
.B \-man
macro package, or
.BR aroff (1)
source files prepared with
.B "Appleworks GS"
(tm) or a compatible word processor.
.SS "Referring to Other Manual Pages"
Other manual pages can be referenced in one of two ways, depending on
whether the target manual page is an
.BR aroff
or
.BR nroff
source file.
.LP
For
.BR aroff
source files, a "link" may be made by creating a file ending in
.BR ".l"
(that's a dot-ell). The file must contain a single line consisting
of the pathname of the target
.BR aroff
source file.
An intentional design limitation was made that disallows this form
of "link" in the
.BR manl
(that's man-ell) subdirectory.
.LP
For
.BR nroff
source files, a "link" may be made by creating a file containing
the
.BR nroff
source (\fB\.so\fP) command. This file should have the same suffix
as the target
.BR nroff
source file.
.B man
does not itself do any processing of the source command.
.LP
With both types of "links" the pathname may be either a full- or
partial-pathname. In the latter case, the pathname must be relative
to the root of the manual page directory subtree.
.LP
.B man
processes the indicated file in place of the current one.
The reference must be expressed as
a pathname relative to the root of
the manual page directory subtree.
.SS "Preprocessing Manual Pages"
If the first line is a string of the form:
.nf
\fB'\|\e"\0 \fR\fIX\fR
.fi
where
.I X
is separated from the
`\fB"\fP'
by a single
.SM SPACE
and consists of any combination of characters in the following list,
.B man
pipes its input to
.BR troff (1)
or
.BR nroff (1)
through the corresponding preprocessors.
.nf
\fBe\fP \fBeqn\fP(1), or \fBneqn\fP for \fBnroff\fP
\fBr\fP \fBrefer\fP(1)
\fBt\fP \fBtbl\fP(1)
\fBv\fP \fBvgrind\fP(1)
.fi
.LP
If
.B eqn
or
.B neqn
is invoked,
it will automatically read the file
.B /usr/pub/eqnchar
(see
.BR eqnchar (7)).
If
.BR nroff (1)
is invoked,
.BR col (1V)
is automatically used.
.SH "COMPRESSED MANUAL PAGES"
.B man
allows its manual pages to be compressed by either
.BR compress ,
.BR freeze ,
or
.BR gzip ,
in which case the manual page must have the suffix
.BR .Z ,
.BR .F ,
or
.BR .gz ,
respectively. Note that the test for these suffixes is case sensitive
and if the incorrect case is used then the compressed file will be passed
to
.B nroff
with unpredictable results.
.LP
Compression may be used on files in either (or both) of the
.BR man? " and " cat?
subdirectories. Do not compress
.BR aroff (1)
source files since compressed files in the
.BR man?
subdirectory are always assumed to be
.BR nroff (1)
source.
.SH ENVIRONMENT
.IP \fBMANPATH\fP
If set,
its value overrides
.B /usr/man
as the default search path.
(The
.B \-M
flag, in turn, overrides this value.)
See the description of the
.B \-M
flag for syntax details.
.IP \fBUSRMAN\fP
If
.B MANPATH
is not set, then the value of
.B USRMAN
(if set) overrides
.B /usr/man
as the default search path.
(The
.B \-M
flag, in turn, overrides this value.)
See the description of the
.B \-M
flag for syntax details.
.IP \fBMANDIR\fP
If neither
.B MANPATH
nor
.B USRMAN
is set, then the value of
.B MANDIR
(if set) overrides
.B /usr/man
as the default search path.
(The
.B \-M
flag, in turn, overrides this value.)
See the description of the
.B \-M
flag for syntax details.
.IP \fBPAGER\fP
A program to use for interactively delivering
.BR man 's
output to the screen.
If not set,
.RB ` "/bin/more" '
(see
.BR more (1))
is used.
.IP \fBTCAT\fP
The name of the program to use to display
.BR troff ed
manual pages.
If not set,
.RB ` "lpr \-t" '
(see
.BR lpr (1))
is used.
.IP \fBTROFF\fP
The name of the formatter to use when the
.B \-t
flag is given.
If not set,
.RB ` "troff \-t" '
is used.
.SH FILES
.B /usr/[share]/man
.RS
root of the standard manual page directory subtree
.RE
.sp
.B /usr/[share]/man/man?/*
.RS
unformatted manual entries
.RE
.sp
.B /usr/[share]/man/cat?/*
.RS
.BR nroff ed
manual entries
.RE
.sp
.B /usr/[share]/man/fmt?/*
.RS
.BR troff ed
manual entries
.RE
.sp
.B /usr/[share]/man/whatis
.RS
table of contents and keyword database
.RE
.sp
.B /usr/[share]/lib/tmac/tmac.an
.RS
standard
.B \-man
macro package
.RE
.sp
.B /usr/pub/eqnchar
.SH "SEE ALSO"
.BR apropos (1),
.BR aroff (1),
.BR cat (1V),
.BR col (1V),
.BR compress (1),
.BR eqn (1),
.BR freeze (1),
.BR gzip (1),
.BR less (1),
.BR lpr (1),
.BR more (1),
.BR nroff (1),
.BR refer (1),
.BR tbl (1),
.BR troff (1),
.BR vgrind (1),
.BR vtroff (1),
.BR whatis (1),
.BR whereis (1),
.BR eqnchar (7),
.BR man (7),
.BR catman (8)
.br
.ne 5
.SH NOTES
.LP
Because
.B troff
is not 8-bit clean,
.B man
has not been made 8-bit clean.
.LP
The
.B \-f
and
.B \-k
options use the
.B whatis
database, which is created by
.BR makewhatis (8).
.br
.ne 4
.LP
Although this version of
.B man
allows
.BR USRMAN " and " MANDIR
to be each a colon- or space-separated list of pathnames, other versions
of
.B man
treat the values of these environment variables as a single pathname.
For compatibility reasons, the use of these two environment variables
is discouraged; use
.B MANPATH
instead.
.SH BUGS
.LP
The manual is supposed to be reproducible
either on a phototypesetter or on an
.SM ASCII
terminal.
However,
on a terminal some information
(indicated by font changes, for instance)
is necessarily lost.
.LP
Some dumb terminals cannot process the vertical motions produced
by the
.B e
.RB ( eqn (1))
preprocessing flag.
To prevent garbled output on these terminals,
when you use
.B e
also use
.BR t ,
to invoke
.BR col (1V)
implicitly.
This workaround has the disadvantage of eliminating superscripts and
subscripts \(em even on those terminals that can display them.
.SM CTRL-Q
will clear a terminal that gets confused by
.BR eqn (1)
output.
.LP
The code which calls the
.BR eqn (1),
.BR refer (1),
.BR tbl (1),
and
.BR vgrind (1)
preprocessors is not yet implemented. Since these preprocessors do
not as yet exist for GNO, this is not too much of a problem.
.LP
Please report any other bugs to Devin Reade, <gdr@myrias.com>.
.SH HISTORY
The GNO version of
.BR man
first appeared in GNO version 1.0 and was written by Mike Horwath.
This version was rewritten from scratch by Devin Reade.

View File

@ -1,154 +0,0 @@
/*
* Copyright 1995 by Devin Reade <gdr@myrias.com>. For distribution
* information see the README file that is part of the manpack archive,
* or contact the author, above.
*/
segment "man_______";
#include <stdio.h>
#include <getopt.h>
#include <string.h>
#include <stdlib.h>
#include <libc.h>
#include <ctype.h>
#include <assert.h>
#include <sgtty.h>
#include <unistd.h>
#include "util.h"
#include "man.h"
#ifdef DEBUG
extern void begin_stack_check(void);
extern int end_stack_check(void);
#endif
char *macroPackage = "an"; /* default /usr/lib/tmac/tmac.an */
char *versionStr = "Version 3.0 by Devin Reade";
char *pager;
char *troff;
char *tcat;
static char *nothing = "nothing appropriate";
short f_flag, k_flag, M_flag, n_flag, t_flag, T_flag, V_flag;
short hyphen_flag, err_flag;
static void usage(char *progname) {
if (err_flag || V_flag) fprintf(stderr,"%s %s\n",progname,versionStr);
if (err_flag) {
fprintf(stderr,"Usage:\n\
\t%s [-] [-nt] [-M path] [-T macro-package] [section] title ...\n\
\t%s [-n] [-M path] -f filename ...\n\
\t%s [-n] [-M path] -k keyword ...\n\n",progname,progname,progname);
exit(1);
}
return;
}
int main (int argc, char **argv) {
int i, result;
char *p;
extern int optind;
extern char *optarg;
/* make sure Gno is running */
if (needsgno()==0) {
fprintf(stderr,"Requires Gno/ME\n");
return 1;
}
#ifdef STACK_CHECK
begin_stack_check();
#endif
/*
* initialization
*/
f_flag = k_flag = M_flag = t_flag = T_flag = V_flag = 0;
n_flag = hyphen_flag = err_flag = 0;
/*
* parse the command line
*/
while((i = getopt(argc,argv,"fkM:ntT:V-")) != EOF) {
switch(i) {
case 'f':
f_flag++;
if (k_flag || t_flag || T_flag || hyphen_flag) err_flag++;
break;
case 'k':
k_flag++;
if (f_flag || t_flag || T_flag || hyphen_flag) err_flag++;
break;
case 'M':
M_flag++;
manpath = Xstrdup(optarg,__LINE__,__FILE__);
break;
case 'n':
n_flag++;
break;
case 't':
t_flag++;
if (k_flag || f_flag) err_flag++;
break;
case 'T':
T_flag++;
macroPackage = optarg;
if (k_flag || f_flag) err_flag++;
break;
case 'V':
V_flag++;
break;
default:
err_flag++;
}
}
/* take care of the '-' option, since getopt isn't smart enough */
for (i=optind; i<argc; i++) {
if (strcmp(argv[i],"-") == 0) {
hyphen_flag++;
if (k_flag || f_flag) err_flag++;
--argc;
for( ; i<argc; i++) {
argv[i] = argv[i+1];
}
}
}
if ((argc == optind) || (!k_flag && !f_flag && (argc-optind > 3))) {
err_flag++;
}
usage(argv[0]);
/* if not already done, set the manpath */
if (!M_flag) manpath = getManpath();
i = 0;
if (k_flag || f_flag) {
result = apropos(argc-optind, &argv[optind],
((k_flag) ? MAN_K_MODE : MAN_F_MODE));
if (!n_flag) {
i = apropos(argc-optind, &argv[optind],
((k_flag) ? ORCA_K_MODE : ORCA_F_MODE));
}
if (result<=0 && i<=0) {
fprintf(stderr,"%s: %s\n",basename(argv[0]),nothing);
}
} else {
if (!isatty(STDOUT_FILENO)) hyphen_flag++;
result = man(argc-optind, &argv[optind]);
}
free(manpath);
result = ((result == 0) && (i == 0)) ? 0 : 1;
#ifdef STACK_CHECK
fprintf(stderr,"stack usage: %d bytes\n",end_stack_check());
#endif
return result;
}

View File

@ -1,95 +0,0 @@
/*
* Copyright 1995 by Devin Reade <gdr@myrias.com>. For distribution
* information see the README file that is part of the manpack archive,
* or contact the author, above.
*/
/*
* Configuration info
*/
#define WHATIS "whatis"
#define PAGER "/bin/more"
#define SYSCMND "15/syscmnd"
#define AROFF "aroff"
#define NROFF "nroff"
#define TROFF "troff -t"
#define TCAT "lpr -t"
#define CAT "cat"
#define EQN "eqn"
#define REFER "refer"
#define TBL "tbl"
#define VGRIND "vgrind"
#define NON 0x00
#define TXT 0x04
#define BIN 0x06
#define SRC 0xB0
#define MAN_F_MODE 1
#define MAN_K_MODE 2
#define WHATIS_MODE 3
#define ORCA_F_MODE 4
#define ORCA_K_MODE 5
#define ORCA_W_MODE 6
#define BUFFERSIZE 2048
typedef struct Section_tag {
char *name; /* section name */
char *suffix; /* directory suffix */
} Section;
typedef struct {
char *suffix;
char *extractor;
} compressionType;
/*
* from globals.c
*/
extern compressionType compressArray[];
extern char linebuf[BUFFERSIZE];
extern char linebuf2[BUFFERSIZE];
/*
* from man.c
*/
extern Section sections[];
extern char *manpath;
extern char *pager;
extern char *tcat;
extern char *troff;
extern char *macroPackage;
extern short hyphen_flag;
extern short n_flag;
extern short t_flag;
/*
* from apropos2.c
*/
int apropos(int argc, char **argv, int whole_line);
/*
* from whatis2.c
*/
int whatis(int argc, char **argv);
/*
* from man2.c
*/
int man (int argc, char *argv[]);
/*
* from common.c
*/
int getSuffixIndex(char *name);

View File

@ -1,611 +0,0 @@
/*
* Copyright 1995 by Devin Reade <gdr@myrias.com>. For distribution
* information see the README file that is part of the manpack archive,
* or contact the author, above.
*/
segment "man2______";
#include <sys/types.h>
#include <sys/stat.h>
#include <dirent.h>
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <ctype.h>
#include <unistd.h>
#include <errno.h>
#include <fcntl.h>
#include <sgtty.h>
#include "util.h"
#include "man.h"
#define MAX(a,b) ((a) > (b)) ? (a) : (b)
static char **buildManList(char *suffix, char *name);
static void display(char *list);
static char *getBaseName (char *out, char *in);
static void cleanManList(char **list);
/*
* Pre: argc is the number of strings in argv. It should either be 1 or 2.
* If DEBUG is defined, then any other value of argc will result in
* a failed assert.
*
* argv is an array of strings. If argc==1, then argv[0] is presumed
* to be the name of the man page. If argc==2, then argv[0] is
* presumed to be a section number and argv[1] is the name of the
* man page.
*
* globals:
* manpath must be a malloc'd string. Either ':' or ' ' may
* may be used as a directory delimiter.
* macroPackage must be set to a static string.
* t_flag must be in a defined state (either set or unset)
* hyphen_flag must be in a defined state (either set or unset)
*
* Post: print the man page in whatever form it takes, acting as necessary
* on the -, -M, and -T flags and section number.
*/
int man(int argc, char *argv[]) {
char **manpath_array, **manpagelist;
char *sec, *name, *current_path;
Section *section;
int i, j, k, abort;
short section_found, page_found;
char dirbrk; /* path component separator. either ':' or '/' */
char c, *p;
struct sgttyb termMode;
short oldMode;
/* initialization */
abort = 0;
section_found = 0;
page_found = 0;
if (t_flag) {
if ((tcat = getenv("TCAT")) == NULL) {
tcat = TCAT;
} else tcat = Xstrdup(tcat,__LINE__,__FILE__);
if ((troff = getenv("TROFF")) == NULL) {
troff = TROFF;
} else troff = Xstrdup(troff,__LINE__,__FILE__);
}
if (hyphen_flag) {
pager = CAT;
} else if ((pager = getenv("PAGER")) == NULL) {
pager = PAGER;
}
/* determine name and, if appropriate, sec */
switch (argc) {
case 1:
sec = NULL;
name = argv[0];
break;
case 2:
sec = argv[0];
/* special case some section abbreviations */
if (!strcmp(sec,"l")) {
sec = "local";
} else if (!strcmp(sec,"n")) {
sec = "new";
} else if (!strcmp(sec,"o")) {
sec = "old";
} else if (!strcmp(sec,"p")) {
sec = "public";
}
name = argv[1];
break;
default:
fprintf(stderr,"internal error at line %d in file %s\n",__LINE__,
__FILE__);
exit(1);
}
/* create array of paths to search */
if ((manpath_array = makePathArray(manpath)) == NULL) return 1;
/*
* loop over all the paths in MANPATH
*/
i=0;
current_path = manpath_array[i];
while (!abort && current_path) {
dirbrk = (strchr(current_path,':')!=NULL) ? ':' : '/';
/* go to the current path in MANPATH */
if (chdir(current_path) == -1) {
i++;
current_path = manpath_array[i];
continue;
}
/* loop over sections */
for (j=0; !abort && sections[j].name != NULL; j++) {
/*
* if section number was specified and this isn't it, do
* the next loop
*/
if (sec && (strcmp(sec,sections[j].name) ||
(!isdigit(*sec) &&
strncmp(sec,sections[j].name,strlen(sec))))) continue;
section_found++;
/*
* we're going to check this section. Get the pathnames
* (relative to this directory) of the two files.
*/
manpagelist = buildManList(sections[j].suffix,name);
if (!manpagelist) continue;
page_found++;
for (k=0; !abort && manpagelist[k]; k++) {
display(manpagelist[k]);
if (!hyphen_flag && !t_flag) {
fprintf(stderr,
"type q to quit, or any other key for next man page: ");
c = getcharraw();
if (c == '\0') {
fprintf(stderr,"getcharraw failed line %d of %s: %s\n",
__LINE__,__FILE__,strerror(errno));
exit(1);
}
fputc('\n',stderr);
/* evaluate result */
if ((c == 'q') || (c == 'Q')) abort++;
}
}
cleanManList(manpagelist);
} /* done looping over sections */
i++;
current_path = manpath_array[i];
} /* done looping over paths */
i = 0; /* used here for the return code */
if (sec) {
if (!section_found) {
fprintf(stderr,"there is no section %s in the manual\n",sec);
i++;
} else if (!page_found) {
fprintf(stderr,"there is no %s in section %s\n",name,sec);
i++;
}
} else if (!page_found) {
fprintf(stderr,"there is no %s in the manual\n",name);
i++;
}
return i;
}
#define DIRBUF_LEN 10
static const char *manstr="man";
static const char *catstr="cat";
static char **buildManList(char *suffix, char *name) {
static char buffer1[FILENAME_MAX];
static char buffer2[FILENAME_MAX];
DIR *directory;
struct dirent *entry;
char **list1, **list2, **list3;
size_t len;
int total1, total2, i, j, k;
char *p, *fn;
/* initialization */
list1 = list2 = list3 = NULL;
total1 = total2 = 0;
#ifdef DEBUG
/* sanity check on arguments */
if(MAX(strlen(manstr),strlen(catstr)) + strlen(suffix) >= FILENAME_MAX) {
fprintf(stderr,"internal error: buffer overflow at line %d of %s\n",
__LINE__,__FILE__);
}
#endif
/*
* look in man subdirectory
*/
strcpy(buffer1,manstr);
strcat(buffer1,suffix);
if ((directory = opendir(buffer1)) != NULL) {
while ((entry = readdir(directory)) != (struct dirent *) NULL) {
/* skip if no match */
len = strlen(name);
if (strncmp(entry->d_name,name,len) ||
(entry->d_name[len] != '.')) continue;
if (strlen(manstr) + strlen(suffix) + strlen(entry->d_name) +
strlen(suffix) + 1 >= FILENAME_MAX) {
fprintf(stderr,"internal error: buffer overflow at line %d of %s\n",
__LINE__,__FILE__);
}
sprintf(buffer1,"%s%s:%s",manstr,suffix,entry->d_name);
/* look for "links" to aroff files. (what a kludge) */
if ((buffer1[3] != 'l') &&
(strcmp(".l",&buffer1[strlen(buffer1)-2])==0)) {
FILE *linkptr;
char *tp;
/* dereference the "link" */
if ((linkptr = fopen(buffer1,"r")) == NULL) {
fprintf(stderr,"couldn't open %s\n",buffer1);
} else if (fgets(buffer2,FILENAME_MAX,linkptr)==NULL) {
fprintf(stderr,"couldn't read %s\n",buffer1);
} else {
/* drop trailing space and newline */
tp = buffer2 + strlen(buffer2) -1;
while ((tp>=buffer2) && (isspace(*tp) || *tp == '\n')) {
*tp = '\0';
tp--;
}
fclose(linkptr);
if (access(buffer2,R_OK) == 0) {
list1 = addToStringArray(list1, buffer2);
total1++;
}
}
} else {
/* not a .l "link"; a normal file */
list1 = addToStringArray(list1, buffer1);
total1++;
}
}
closedir(directory);
}
if (!t_flag) {
/*
* look in cat subdirectory
*/
strcpy(buffer1,catstr);
strcat(buffer1,suffix);
if ((directory = opendir(buffer1)) != NULL) {
while ((entry = readdir(directory)) != (struct dirent *) NULL) {
/* skip if no match */
len = strlen(name);
if (strncmp(entry->d_name,name,len) ||
(entry->d_name[len] != '.')) continue;
if (strlen(catstr) + strlen(suffix) + strlen(entry->d_name) +
strlen(suffix) + 1 >= FILENAME_MAX) {
fprintf(stderr,"internal error: buffer overflow at line %d of %s\n",
__LINE__,__FILE__);
}
sprintf(buffer1,"%s%s:%s",catstr,suffix,entry->d_name);
list2 = addToStringArray(list2, buffer1);
total2++;
}
closedir(directory);
}
}
/*
* eliminate files common to both lists
*/
len = strlen(suffix);
for(i=0; i<total1; i++) {
if (list1[i] == NULL) continue;
for (j=0; j<total2; j++) {
if (list2[j] == NULL) continue;
getBaseName(buffer1,list1[i]);
getBaseName(buffer2,list2[j]);
#ifdef DEBUG
if ((strlen(buffer1) < len + 5) ||
(strlen(buffer2) < len + 5)) {
fprintf(stderr,"internal error at line %d of %s\n",__LINE__,
__FILE__);
exit(1);
}
#endif
/* match after the respective "manXX/" and "catXX/" */
if ( strcmp(&buffer1[len+4],&buffer2[len+4]) == 0 ) {
p = newerFile(list1[i],list2[j]);
if (p == list1[i]) {
free(list2[j]);
list2[j] = NULL;
} else if (p == list2[j]) {
free(list1[i]);
list1[i] = NULL;
break;
} else {
fprintf(stderr,"internal error at line %d of %s\n\t%s\n\t%s\n",
__LINE__,__FILE__,
(list1[i]) ? list1[i] : "(NULL)",
(list2[j]) ? list2[j] : "(NULL)");
perror("newerFile failed");
exit(1);
}
} /* endif */
} /* endfor */
} /* endfor */
/*
* combine the two lists
*/
for (i=0;i<total1;i++) {
if (list1[i] != NULL) {
list3 = addToStringArray(list3, list1[i]);
free(list1[i]);
}
}
for (j=0;j<total2;j++) {
if (list2[j] != NULL) {
list3 = addToStringArray(list3, list2[j]);
free(list2[j]);
}
}
free(list1);
free(list2);
return list3;
}
/*
* cleanManList
*
* Pre: list is a NULL-terminated array of strings, where the array
* and each string in the array was allocated by malloc.
*
* Post: all malloc'd memory in list is free'd.
*/
static void cleanManList(char **list) {
int i;
for (i=0; list[i]; i++) {
free(list[i]);
}
free (list);
return;
}
/*
* display
*/
#define MANSUBDIR 0
#define CATSUBDIR 1
#define FORMAT "Formatting manual page, please wait ..."
#define DECOMP "Decompressing manual page, please wait ..."
#define DECFOR "Decompressing and formatting manual page, please wait ..."
#define OVERFLOW "Internal buffer overflow ... aborted."
static void display(char *file) {
int icompress, isubdir;
char *tmac;
char *roffer;
char *compressor;
fileType *ft;
#ifdef DEBUG
if (file == NULL) {
fprintf(stderr,"internal error line %d of %s\n",__LINE__,__FILE__);
exit(1);
}
if (strlen(file) < 4) {
fprintf(stderr,"internal error line %d of %s\n",__LINE__,__FILE__);
exit(1);
}
#endif
/*
* determine which subdirectory this file is in
*/
if (strncmp(file,"cat",3) == 0) {
isubdir = CATSUBDIR;
} else {
isubdir = MANSUBDIR;
}
/*
* if we're troffing a new file to fmt?, make sure the directory
* exists
*/
if (t_flag && hyphen_flag) {
char *p;
struct stat sbuf;
/* ensure the fmt? directory exists */
sprintf(linebuf,"fmt%s",&file[3]);
if ((p = strchr(linebuf,':')) != NULL) {
*p = '\0';
#ifdef DEBUG
} else if ((p = strchr(linebuf,'/')) == NULL) {
fprintf(stderr,"internal error line %d of %s\n",__LINE__,
__FILE__);
exit(1);
#endif
} else *p = '\0';
if (stat(linebuf,&sbuf) != 0) {
fprintf(stderr,"couldn't stat %s: %s. %s skipped\n",
linebuf,strerror(errno),file);
return;
} else if (!(sbuf.st_mode & S_IFDIR)) {
fprintf(stderr,"cannot access %s: %s. %s skipped\n",
linebuf,strerror(ENOTDIR),file);
return;
}
}
/*
* determine the type of compression used, if any
*/
icompress = getSuffixIndex(file);
if (icompress >= 0) {
compressor = compressArray[icompress].extractor;
if (isubdir == MANSUBDIR) {
/*
* compressed nroff source
*/
if (t_flag && hyphen_flag) {
if (strlen(compressor) + 2*strlen(file) + strlen(troff) +
strlen(macroPackage) + strlen(tcat) + 12 > BUFFERSIZE) {
fprintf(stderr,"%s\n",OVERFLOW);
exit(1);
}
sprintf(linebuf,"%s %s | %s -m%s - > fmt%s",
compressor, file, troff, macroPackage, &file[3]);
} else if (t_flag) {
if (strlen(compressor) + strlen(file) + strlen(troff) +
strlen(macroPackage) + strlen(tcat) + 12 > BUFFERSIZE) {
fprintf(stderr,"%s\n",OVERFLOW);
exit(1);
}
sprintf(linebuf,"%s %s | %s -m%s - | %s",
compressor, file, troff, macroPackage, tcat);
} else {
/* not troff, jes' plain old nroff */
if (strlen(compressor) + strlen(file) + strlen(NROFF) +
strlen(macroPackage) + strlen(pager) + 12 > BUFFERSIZE) {
fprintf(stderr,"%s\n",OVERFLOW);
exit(1);
}
if (!hyphen_flag) printf("%s\n",DECFOR);
sprintf(linebuf,"%s %s | %s -m%s - | %s",
compressor, file, NROFF, macroPackage, pager);
}
} else {
/*
* compressed straight text
*/
if (strlen(compressor)+strlen(file)+strlen(pager)+5 > BUFFERSIZE) {
fprintf(stderr,"%s\n",OVERFLOW);
exit(1);
}
if (!hyphen_flag) printf("%s\n",DECOMP);
sprintf(linebuf,"%s %s | %s", compressor, file, pager);
}
} else {
if (isubdir == MANSUBDIR) {
/*
* Can be either aroff or nroff source. If it's nroff source,
* it must either be a TXT, SRC, or BIN file
*/
if (!hyphen_flag && !t_flag) printf("%s\n",FORMAT);
if ((ft = getFileType(file)) == NULL) {
perror(file);
exit(1);
}
if ((ft->type == 0x50) || (ft->auxtype == 0x8010)) {
/*
* AppleworksGS Word Processor format; use 'aroff'
*/
if (t_flag) {
fprintf(stderr,"cannot use troff on aroff source files\n");
return;
}
if (strlen(AROFF)+strlen(file)+strlen(pager)+5 > BUFFERSIZE) {
fprintf(stderr,"%s\n",OVERFLOW);
exit(1);
}
sprintf(linebuf,"%s %s | %s", AROFF, file, pager);
} else if ((ft->type == TXT) || (ft->type == BIN) ||
(ft->type == SRC) || (ft->type == NON)) {
/*
* TeXT, BINary, or SouRCe file; assume nroff source
*/
if (t_flag && hyphen_flag) {
if (strlen(troff) + strlen(macroPackage) +
2 * strlen(file) + 7 >= BUFFERSIZE) {
fprintf(stderr,"%s\n",OVERFLOW);
exit(1);
}
sprintf(linebuf,"%s -m%s %s > fmt%s",
troff, macroPackage, file, &file[3]);
} else if (t_flag) {
if (strlen(troff) + strlen(macroPackage) + strlen(file) +
strlen(tcat) + 7 >= BUFFERSIZE) {
fprintf(stderr,"%s\n",OVERFLOW);
exit(1);
}
sprintf(linebuf,"%s -m%s %s | %s",troff,macroPackage,file,tcat);
} else {
/* not troff, jes' plain old nroff */
if (strlen(NROFF) + strlen(macroPackage) +
strlen(file) + strlen(pager) + 8 >= BUFFERSIZE) {
fprintf(stderr,"%s\n",OVERFLOW);
exit(1);
}
sprintf(linebuf,"%s -m%s %s | %s",NROFF,macroPackage,file,pager);
}
} else {
fprintf(stderr,
"bad file type for %s\n\ttype = %x\n\taux = %lx\n",
file,ft->type,ft->auxtype);
return;
}
} else {
/* assume straight text */
if (strlen(CAT) + strlen(file) + strlen(pager) + 4 >= BUFFERSIZE){
fprintf(stderr,"%s\n",OVERFLOW);
exit(1);
}
sprintf(linebuf,"%s %s | %s", CAT, file, pager);
}
}
#if 0
fprintf(stderr,"DEBUG: BUFFER: %s\n",linebuf);
#endif
system(linebuf);
return;
}
/*
* getBaseName -- copy the filename pointed to by <in> into the buffer
* pointed to by <out>, dropping any compression suffix
* that may be on the base name. The set of compression
* suffixes is defined by the NULL-terminated compressArray[].
*
* It is the user's responsibility to ensure that the
* buffer *out has been allocated with sufficient space
* for the result.
*
* Returns a pointer to <out>.
*/
static char *getBaseName (char *out, char *in) {
char *p;
int i;
strcpy(out,in);
if ((p = strrchr(out,'.')) != NULL) {
for (i=0; compressArray[i].suffix; i++) {
if (strcmp(p,compressArray[i].suffix)==0) {
*p = '\0';
break;
}
}
}
return out;
}

View File

@ -1,234 +0,0 @@
/*
* Copyright 1995 by Devin Reade <gdr@myrias.com>. For distribution
* information see the README file that is part of the manpack archive,
* or contact the author, above.
*/
segment "makewhatis";
#include <stdio.h>
#include <string.h>
#include <ctype.h>
#include <unistd.h>
#include <stdlib.h>
#include <gsos.h>
#include <orca.h>
#include "makewhatis.h"
/* These are the compression types */
#define NO_COMPRESS 0
#define Z_COMPRESS 1
#define F_COMPRESS 2
#define G_COMPRESS 3
#ifdef TEST_PROCESS
short v_flag = 1;
FILE *output_fp;
FILE *error_fp;
#else
extern FILE *output_fp;
extern FILE *error_fp;
#endif
extern GSString255Ptr __C2GSMALLOC (char *s);
extern char buffer[];
extern char titlebuf[];
/*
* void process (char *filename, char *tmp_file, FILE *whatis_fp);
*
* Pre: <filename> is the name of the file to add to the database.
* <tmp_file> is the name for the temporary file. It has not been opened.
* <whatis_fp> is a file pointer to the open whatis database file.
* (sec> is the section "number". We really only care if it is
* either "l" or "local" (because of aroff "links"), otherwise
* it is ignored.
*
* Post: The name, section number, and description from the man page is
* appended to <whatis_fp>.
*/
void process (char *filename, char *tmp_file, FILE *whatis_fp, char *sec) {
FileInfoRecGS info_record; /* used to get the file type */
char *suffix; /* points to the start of the file suffix */
static char command_buf[255]; /* used to call system(2) */
char *p1; /* a scratch pointer */
int namelength; /* length of 'name (section)' */
char *name; /* points to the file basename */
short compression; /* the compression type (if nec) */
if (v_flag>=2) fprintf(output_fp,"Working on file %s/%s ...\n",sec,filename);
/*
* get the file basename
*/
if ((name = malloc (strlen(filename)+1)) == NULL) {
if (v_flag)
fprintf(error_fp,"malloc failed when processing %s -- file skipped\n",
filename);
return;
}
strcpy(name,filename);
/*
* check for a compression suffix like ".Z" or ".F"
*/
p1 = name + strlen(name) -1; /* p1 points to last char of name */
while ((p1>=name) && (*p1!='.')) p1--;
if (p1<=name) { /* <= because we don't want a name beginning with '.' */
if (v_flag)
fprintf(error_fp,"%s has no suffix -- file skipped\n",
filename);
return;
}
if (strcmp(p1,".Z")==0) {
compression = Z_COMPRESS;
} else if (strcmp(p1,".F")==0) {
compression = F_COMPRESS;
} else if (strcmp(p1,".gz")==0) {
compression = G_COMPRESS;
} else compression = NO_COMPRESS;
*p1 = '\0';
/*
* define the suffix
*/
if (compression == NO_COMPRESS) {
suffix = p1 + 1;
} else {
while ((p1>=name) && (*p1!='.')) --p1;
if (p1<=name) { /* <= because we don't want a name beginning with '.' */
if (v_flag)
fprintf(error_fp,"%s has deformed file name -- file skipped\n",
filename);
return;
}
*p1 = '\0';
suffix = p1 + 1;
}
/*
* find out the file type
*/
if (compression == NO_COMPRESS) {
info_record.pCount = 5;
info_record.pathname = __C2GSMALLOC(filename);
GetFileInfoGS(&info_record);
if (toolerror()) {
if (v_flag)
fprintf(error_fp,
"malloc failed when processing %s -- file skipped\n", filename);
return;
}
}
/*
* Process the file according to type: nroff, aroff, freeze, and compress.
* The digested result is placed in buffer.
*/
if ((compression == NO_COMPRESS) &&
(info_record.fileType == 0x50u) &&
(info_record.auxType == 0x8010u)
) {
/* is it an Appleworks GS word processor document? Use aroff */
sprintf(command_buf,"aroff -b %s > %s",filename,tmp_file);
if (v_flag>=3) fprintf(stderr,"%s\n",command_buf);
system(command_buf);
fillbuffer(tmp_file);
} else if (compression == Z_COMPRESS) {
/* Compressed man page; uncompress it */
sprintf(command_buf,"compress -cd %s > %s",filename,tmp_file);
if (v_flag>=3) fprintf(stderr,"%s\n",command_buf);
system(command_buf);
fillbuffer(tmp_file);
} else if (compression == F_COMPRESS) {
/* Frozen man page; melt it */
sprintf(command_buf,"freeze -cd %s > %s",filename,tmp_file);
if (v_flag>=3) fprintf(stderr,"%s\n",command_buf);
system(command_buf);
fillbuffer(tmp_file);
} else if (compression == G_COMPRESS) {
/* gzipped man page; zcat it */
sprintf(command_buf,"gzip -cd %s > %s",filename,tmp_file);
if (v_flag>=3) fprintf(stderr,"%s\n",command_buf);
system(command_buf);
fillbuffer(tmp_file);
} else if ((*suffix=='l') && (*(suffix+1)=='\0') &&
strcmp("l",sec) && strcmp("local",sec)) {
/* It's a link to another man page; do nothing. */
return;
} else {
/* Assume that it's a text file */
if (v_flag>=3) fprintf(stderr,"assuming text file\n");
fillbuffer(filename);
}
/*
* If there was an error, or it is an .so reference to another man
* page, then return without writing anything to the database
*/
if ((buffer[0] == '\0') || (titlebuf[0] == '\0')) {
return;
}
/*
* At this point, buffer contains the line that we need to print to
* whatis_fd. Strip off any leading spaces, then give it a nice
* formatting.
*/
p1 = buffer;
while (isspace(*p1)) p1++;
namelength = strlen(titlebuf) + strlen(suffix) + 4;
if (namelength > (TABLENGTH * 3)) {
fprintf(whatis_fp,"%s (%s) - %s\n", titlebuf, suffix, p1);
} else if (namelength > (TABLENGTH * 2)) {
fprintf(whatis_fp,"%s (%s)\t- %s\n", titlebuf, suffix, p1);
} else if (namelength > TABLENGTH ) {
fprintf(whatis_fp,"%s (%s)\t\t- %s\n", titlebuf, suffix, p1);
} else {
fprintf(whatis_fp,"%s (%s)\t\t\t- %s\n", titlebuf, suffix, p1);
}
return;
}
#ifdef TEST_PROCESS
int main (int argc, char **argv) {
output_fp = stdout;
error_fp = stderr;
if (argc != 2) {
fprintf(stderr,"Usage: %s <man_page_file_name>\n",argv[0]);
return -1;
}
process (argv[1], ":tmp:garbage", stdout, "2");
return 0;
}
#endif

View File

@ -1,386 +0,0 @@
/*
* Copyright 1995 by Devin Reade <gdr@myrias.com>. For distribution
* information see the README file that is part of the manpack archive,
* or contact the author, above.
*/
segment "util______";
#include <sys/stat.h>
#include <stdlib.h>
#include <string.h>
#include <stdio.h>
#include <errno.h>
#include <assert.h>
#include <unistd.h>
#include <ctype.h>
#include <sgtty.h>
#include <fcntl.h>
#include "util.h"
/*
* getManpath -- return a malloc'd copy of the MANPATH. If MANPATH
* isn't defined in the environment, then use USRMAN, then
* MANDIR, then if all else fails, use the macro DEFAULT_MANPATH.
* If an error occurs, print the cause via perror and exit.
*/
char *getManpath(void) {
char *manpath;
manpath = getenv("MANPATH");
if (manpath == NULL) manpath = getenv("USRMAN");
if (manpath == NULL) manpath = getenv("MANDIR");
if (manpath == NULL) manpath = DEFAULT_MANPATH;
return Xstrdup(manpath,__LINE__,__FILE__);
}
/*
* Xstrdup - a safe strdup; it will handle error conditions and exit
* one occurs
*
* line and file are arbitrary, but are expected to be the
* values of __LINE__ and __FILE__ respectively.
*/
char *Xstrdup(char *oldstr, int line, char *file) {
char *newstr;
if ((newstr = malloc(strlen(oldstr)+1)) == NULL) {
fprintf(stderr,"Xstrdup failed at line %d in file %s: %s\n",line,
file,strerror(errno));
exit(1);
}
strcpy(newstr,oldstr);
return newstr;
}
/*
* Xmalloc - a safe malloc; it will handle error conditions and exit
* if one occurs.
*
* line and file are arbitrary, but are expected to be the
* values of __LINE__ and __FILE__ respectively.
*/
void *Xmalloc(size_t size, int line, char *file) {
char *p;
if ((p = malloc(size)) == NULL) {
fprintf(stderr,"Xmalloc failed at line %d in file %s: %s\n",line,
file,strerror(errno));
exit(1);
}
return ((void *) p);
}
/*
* Xrealloc - a safe realloc; it will handle error conditions and exit
* if one occurs.
*
* line and file are arbitrary, but are expected to be the
* values of __LINE__ and __FILE__ respectively.
*/
void *Xrealloc(void *oldptr, size_t size, int line, char *file) {
char *p;
if ((p = realloc(oldptr, size)) == NULL) {
fprintf(stderr,"Xrealloc failed at line %d in file %s: %s\n",line,
file,strerror(errno));
exit(1);
}
return ((void *) p);
}
/*
* addToStringArray -- add a string to a NULL-terminated array of strings.
* If oldArray is NULL, then a new array is created,
* otherwise oldArray is expanded.
*
* WARNING: | Because of the allocation scheme used, any oldArray
* | passed to this routine _must_ be the return value
* | of a previous call to this routine. This does not
* | imply that only one array can be expanded by this
* | routine (any number may be expanded).
*
* The value of macro SLOTS_QUANTUM defined below is
* the number of array slots allocated at one time. The
* size of the string array is always a multiple of this
* value.
*
* Returns a pointer to an array that contains the old
* strings with the new one appended. The array is
* NULL-terminated.
*/
#define SLOTS_QUANTUM 10
char **addToStringArray(char **oldArray, char *string) {
char **result;
int slotsAlloced, slotsUsed;
if (oldArray == NULL) {
/*
* This is a new array; do the brute force approach
*/
result = Xmalloc(SLOTS_QUANTUM * sizeof(char *), __LINE__, __FILE__);
result[0] = Xstrdup(string,__LINE__,__FILE__);
result[1] = NULL;
} else {
/*
* adding to and, if necessary, expanding an old array
*/
/* determine slotsUsed and slotsAlloced */
for (slotsUsed=0; oldArray[slotsUsed]; slotsUsed++);
if (slotsUsed % SLOTS_QUANTUM == SLOTS_QUANTUM-1) { /* space for NULL */
slotsAlloced = slotsUsed+1;
} else {
slotsAlloced = ((slotsUsed / SLOTS_QUANTUM) + 1) * SLOTS_QUANTUM;
}
#ifdef DEBUG
assert(slotsUsed < slotsAlloced);
#endif
/* expand number of slots if necessary */
if (slotsUsed+1 < slotsAlloced) {
/* there are enough slots; add it to this array */
result = oldArray;
} else {
/* we need more slots; expand the array */
slotsAlloced += SLOTS_QUANTUM;
result = Xrealloc(oldArray, slotsAlloced * sizeof(char *),
__LINE__, __FILE__);
}
/* add the string to the array */
result[slotsUsed++] = Xstrdup(string, __LINE__, __FILE__);
result[slotsUsed] = NULL;
}
return result;
}
/*
* makePathArray -- parse a path list and break it into a NULL-terminated
* array of paths. The original path is left unchanged.
*
* The delimiter between paths may either be a ' ' or a ':'.
* The delimiter is assumed to be a ':' if <path> contains
* both '/' and ':' characters but no ' ' character,
* otherwise the delimiter is assumed to be a ' '.
*/
char **makePathArray(char *path) {
char *delim, *p, *q, **result;
/* set the delimiter */
if ( strchr(path,' ')==NULL &&
strchr(path,':') &&
strchr(path,'/')) {
delim = ":";
} else {
delim = " ";
}
/* build the array */
p = Xstrdup(path, __LINE__, __FILE__);
q = strtok(p,delim);
result = NULL;
while (q) {
result = addToStringArray(result, q);
q = strtok(NULL,delim);
}
free(p);
return result;
}
/*
* ncstrcmp -- A case insensitive ("no-case") strcmp
*/
int ncstrcmp(char *a, char *b) {
while (*a && *b) {
if (*a == *b) {
a++; b++;
continue;
}
return ((int) *b - *a);
}
if (!*a && !*b) return 0;
return ((int) *b - *a);
}
/*
* ncstrncmp -- A case insensitive ("no-case") strncmp
*/
int ncstrncmp (char *a, char *b, unsigned int count) {
unsigned int i=0;
for (i=0; i<count; i++) {
if (a[i] == b[i]) {
if (!a[i]) break;
else continue;
}
return ((int) b[i]-a[i]);
}
return 0;
}
/*
* ncstrstr -- A case insensitive ("no-case") strstr
*
* This is implemented using a convert-copy-to-single-case-
* then-strstr hack.
* It's speed could be increased by switching
* to a Boyer-Moore scan algorithm anytime strlen(substr) > 5,
* and using a straight-forward search for strlen(substr) <= 5.
*/
char *ncstrstr(char *str, char *substr) {
char *strCopy, *substrCopy, *p;
strCopy = Xstrdup(str,__LINE__,__FILE__);
substrCopy = Xstrdup(substr,__LINE__,__FILE__);
/* convert the strings */
p = strCopy;
while (*p) {
*p = tolower(*p);
p++;
}
p = substrCopy;
while (*p) {
*p = tolower(*p);
p++;
}
p = strstr(strCopy,substrCopy);
free(strCopy);
free(substrCopy);
return p;
}
/*
* newerFile -- Compares the "last modified" time of two paths.
* Returns:
* the name of the newer file if both files exist
* the second file if both exist and have the same mod time
* the name of the existing file if one file doesn't exist
* NULL and sets errno if neither file exists or if there
* is an error.
*/
char *newerFile(char *path1, char *path2) {
static struct stat record1, record2;
int i,j;
/*
* see if both, only one, or neither files exist
*/
i = access(path1, F_OK);
j = access(path2, F_OK);
if (i==-1 && j==-1) {
errno = ENOENT;
return NULL;
} else if (i==-1) {
return path2;
} else if (j==-1) {
return path1;
}
/*
* both files exist; stat them
*/
if (stat(path1,&record1) != 0) return NULL;
if (stat(path2,&record2) != 0) return NULL;
return (record1.st_mtime > record2.st_mtime) ? path1 : path2;
}
/*
* getcharraw() - return the next character from stdin without waiting
* for a CR to be hit. Returns '\0' and sets errno
* on an error.
*/
#define FAILED_CHAR '\0';
char getcharraw(void) {
short oldmode;
struct sgttyb s;
int count;
char c;
/* obtain old terminal mode */
if (gtty(STDIN_FILENO,&s) == -1) return FAILED_CHAR;
oldmode = s.sg_flags;
/* set terminal to CBREAK and obtain keystroke */
s.sg_flags |= CBREAK;
if (stty(STDIN_FILENO,&s) == -1) return FAILED_CHAR;
count = read (STDIN_FILENO, &c, 1);
/* reset old terminal mode */
s.sg_flags = oldmode;
if ((stty(STDIN_FILENO,&s) == -1) || (count == -1)) return FAILED_CHAR;
return c;
}
/*
* basename -- return a pointer to the base filename (all leading
* pathname components removed) of <path>. <path> _must_
* point to a NULL-terminated string.
*/
char *basename (char *path) {
char *p, dirsep;
dirsep = (strchr(path,':')) ? ':' : '/';
if ((p = strrchr(path,dirsep)) != NULL) {
return p+1;
} else {
return path;
}
}
/*
* dirname -- return a pointer to a string consisting of the directory
* component of <path>. This returns a pointer to an internal
* buffer, so the next call to dirname() will overwrite this
* buffer. <path> must be a NULL-terminated string.
*/
char *dirname (const char *path) {
static char buffer[FILENAME_MAX];
char *p, dirsep;
strcpy(buffer,path);
dirsep = (strchr(buffer,':')) ? ':' : '/';
if ((p = strrchr(buffer,dirsep)) != NULL) {
*p = '\0';
}
return buffer;
}

View File

@ -1,37 +0,0 @@
/*
* Copyright 1995 by Devin Reade <gdr@myrias.com>. For distribution
* information see the README file that is part of the manpack archive,
* or contact the author, above.
*/
/*
* from util.c
*/
#define DEFAULT_MANPATH "/usr/man"
char *getManpath(void);
char *Xstrdup(char *oldstr, int line, char *file);
void *Xmalloc(size_t size, int line, char *file);
void *Xrealloc(void *oldptr, size_t size, int line, char *file);
char **addToStringArray(char **oldArray, char *string);
char **makePathArray(char *path);
int ncstrcmp(char *a, char *b);
int ncstrncmp (char *a, char *b, unsigned int count);
char *ncstrstr(char *str, char *substr);
char *newerFile(char *path1, char *path2);
char getcharraw(void);
char *basename (char *path);
char *dirname (const char *path);
/*
* from utilgs.c
*/
typedef struct {
unsigned int type;
unsigned long int auxtype;
} fileType, fileTypePtr;
fileType *getFileType (char *file);

View File

@ -1,179 +0,0 @@
/*
* Copyright 1995 by Devin Reade <gdr@myrias.com>. For distribution
* information see the README file that is part of the manpack archive,
* or contact the author, above.
*/
segment "utilgs____";
#include <sys/stat.h>
#include <unistd.h>
#include <errno.h>
#include <stdlib.h>
#include <gsos.h>
#include <orca.h>
#include "util.h"
extern GSString255Ptr __C2GSMALLOC(char *);
extern int _mapErr(int);
/*
* access -- a replacement for the standard Gno one; this one will actually
* return 0 when testing X_OK on a directory.
*
* This one still has a bug in it: If the file is a shell command or sys
* file, then X_OK will return zero, but not if it is a shell script (as
* with 'chtyp -lexec filename').
*/
int access(char *name, int mode) {
struct stat statbuf;
int realmode=0;
if (stat(name,&statbuf) == -1) return -1;
/* check read permission */
if ((mode & R_OK) && !(statbuf.st_mode & S_IREAD)) return -1;
/* check write permission */
if ((mode & W_OK) && !(statbuf.st_mode & S_IWRITE)) return -1;
/*
* Check execute mode. Assume directories have execute permission
* for GS/OS.
*/
if (mode & X_OK) {
if (statbuf.st_mode & (S_IFDIR | S_IEXEC)) return 0;
else return -1;
}
return 0; /* file merely exists */
}
/*
* chdir -- Replacement for the one normally shipping with Gno.
* Returns -1 and sets errno on failure, instead of always
* returning zero.
*/
int chdir (const char *pathname) {
PrefixRecGS record;
struct stat statbuf;
int result;
errno = 0;
if (stat(pathname,&statbuf) == -1) return -1;
/* verify that it's a directory */
if (!(statbuf.st_mode & S_IFDIR)) {
errno = ENOTDIR;
return -1;
}
/* change directory */
record.pCount = 2;
record.prefixNum = 0; /* prefix 0 is the current directory */
record.buffer.setPrefix = __C2GSMALLOC(pathname);
if (record.buffer.setPrefix == (GSString255Ptr) NULL) {
errno = ENOMEM;
return -1;
}
SetPrefixGS(&record);
/* verify success, clean up, and return */
result = toolerror();
free(record.buffer.setPrefix);
if (result) {
errno = EINVAL;
return -1;
}
return 0;
}
/*
* getFileType -- Get the file type and auxillary file type of a file.
* On success it returns a pointer to an internal buffer
* containing the file type and aux type. On failure
* it returns NULL and sets errno.
*/
fileType *getFileType (char *file) {
static FileInfoRecGS record;
static fileType result;
int i;
/* set the parameters */
record.pCount = 4;
if ((record.pathname = __C2GSMALLOC(file)) == NULL) {
errno = ENOMEM;
return NULL;
}
/* get the info */
GetFileInfoGS(&record);
/* check for errors */
i = toolerror();
free(record.pathname);
if (i) {
errno = _mapErr(i);
return NULL;
}
/* set the return value */
result.type = record.fileType;
result.auxtype = record.auxType;
return &result;
}
#if 0
#include <stdio.h>
int main(int argc, char **argv) {
char *p;
char buf[1024];
int i;
fileType *ft;
if (argc!=2) return -1;
ft = getFileType(argv[1]);
if (ft == NULL) {
perror(argv[1]);
exit(1);
} else {
printf("type = %x\nauxtype = %lx\n",ft->type,ft->auxtype);
}
return 0;
}
printf("F_OK: %d\n",access(argv[1],F_OK));
printf("R_OK: %d\n",access(argv[1],R_OK));
printf("W_OK: %d\n",access(argv[1],W_OK));
printf("X_OK: %d\n",access(argv[1],X_OK));
if (getwd(buf) == NULL) {
perror("getwd failed");
exit(-1);
}
printf("old directory: %s\n",buf);
if ((i = chdir(argv[1])) !=0) perror ("chdir failed");
printf("chdir returned %d\n",i);
if (getwd(buf) == NULL) {
perror("getwd failed");
exit(-1);
}
printf("new directory: %s\n",buf);
return 0;
}
#endif /* 0 */

View File

@ -1,187 +0,0 @@
.\" This man page is based on another man page copyright (c) 1980
.\" by the Regents of the University of California.
.\" All rights reserved. The Berkeley software License Agreement
.\" specifies the terms and conditions for redistribution.
.\"
.\" While this manual page is based on one from UCB, the included
.\" C source, makefile, and executables are copyright (c) 1995
.\" by Devin Reade <gdr@myrias.com>. All rights reserved.
.\"
.TH WHATIS 1 "Commands and Applications" "24 July 95" "Version 3.0"
.SH NAME
whatis, apropos \- locate commands by name or keyword lookup
.SH SYNOPSIS
.BR apropos
[[
.BI \-M path
] | [
.BI \-m path
]] [
.BR -nV
]
.IR keyword " ..."
.br
.BR whatis
[[
.BI \-M path
] | [
.BI \-m path
]] [
.BR -nV
]
.IR keyword ...
.SH DESCRIPTION
.BR whatis
shows the manual page title line for the specified
.IR keyword (s),
while
.BR apropos
shows which manual pages contain instances of any of the given
.IR keyword (s)
in their title line.
Each word is considered separately and, for
.BR apropos ,
the case of letters is ignored.
Words which are part of other words are considered; when looking for
.IR compile ,
.BR apropos
will also list all instances of
.IR compiler .
.LP
If a line output by either of these commands starts with
.nf
\fIname\fR (\fIsection\fR) ...
.fi
you can enter
.BI man " section name"
to get its documentation.
.SH OPTIONS
.IP "\fB\-M\fP \fIpath\fP"
Override the list of standard directories
.BR apropos
or
.BR whatis
search for the
.BR whatis
database.
The supplied
.I path
must be a colon\- or space\-delimited list of directories.
This search path may also be set using the environment variable
.BR MANPATH .
The space delimiter is provided for compatibility with GS/OS's
use of the colon as a pathname component delimiter. If the search
path contains no spaces nor
.B /
characters (such as
.BR :usr:local:man ),
it is assumed to be a single path, not a list of paths.
If spaces are used as delimiters, remember to quote them from the
shell.
.IP "\fB\-m\fP \fIpath\fP"
Augment the list of standard directories
.BR apropos
or
.BR whatis
search for its database.
The supplied
.I path
must be a colon\- or space\-delimited list of directories.
These directories will be searched after the standard directories
or the directories supplied by the
.BR MANPATH
environment variable are searched.
If spaces are used as delimiters, remember to quote them from the
shell.
.IP \fB-n\fP
Normally, in addition to searching the various
.BR whatis
databases,
.BR apropos
and
.BR whatis
will also search the Orca shell
.BR 15/syscmnd
file. Specifying the
.BR -n
flag will keep
.BR apropos
and
.BR whatis
from searching this file.
.IP \fB-V\fP
Show version information.
.SH ENVIRONMENT
.IP \fBMANPATH\fP
If set,
its value overrides
.B /usr/man
as the list of directories where
.BR apropos
and
.BR whatis
search for their databases.
(The
.B \-M
flag, in turn, overrides this value.)
See the description of the
.B \-M
flag for syntax details.
.IP \fBUSRMAN\fP
If
.B MANPATH
is not set, then the value of
.B USRMAN
(if set) overrides
.B /usr/man
as the list of directories where
.BR apropos
and
.BR whatis
search for their databases.
(The
.B \-M
flag, in turn, overrides this value.)
See the description of the
.B \-M
flag for syntax details.
.IP \fBMANDIR\fP
If neither
.B MANPATH
nor
.B USRMAN
is set, then the value of
.B MANDIR
(if set) overrides
.B /usr/man
as the list of directories where
.BR apropos
and
.BR whatis
search for their databases.
(The
.B \-M
flag, in turn, overrides this value.)
See the description of the
.B \-M
flag for syntax details.
.SH FILES
.\" .IP \fB/usr/\fR[\fBshare/\fR]\fBman/whatis\fR
.BR /usr/ [ share/ ] man/whatis " \-"
The
.BR whatis (1)
database.
.SH BUGS
Please report any bugs to Devin Reade, <gdr@myrias.ab.ca>.
.SH SEE ALSO
.BR man (1),
.BR whereis (1),
.BR catman (8),
.BR makewhatis (8)
.SH HISTORY
The GNO version of
.BR apropos
first appeared in GNO version 1.0 and was written by Mike Horwath.
This version was rewritten from scratch by Devin Reade.

View File

@ -1,110 +0,0 @@
/*
* Copyright 1995 by Devin Reade <gdr@myrias.com>. For distribution
* information see the README file that is part of the manpack archive,
* or contact the author, above.
*/
segment "apropos___";
#include <stdio.h>
#include <getopt.h>
#include <stdlib.h>
#include <libc.h>
#include "util.h"
#include "man.h"
extern int optind;
extern char *optarg;
static char *versionstr = "3.0";
static char *nothing = "nothing appropriate";
extern void begin_stack_check(void);
extern int end_stack_check(void);
int main (int argc, char **argv) {
char *path;
int i, matches1, matches2, matches3;
short V_flag, M_flag, m_flag, n_flag, err_flag;
/* make sure Gno is running */
if (needsgno()==0) {
fprintf(stderr,"Requires Gno/ME\n");
return 1;
}
#ifdef STACK_CHECK
begin_stack_check();
#endif
/* initialization */
V_flag = M_flag = m_flag = n_flag = err_flag = 0;
matches1 = matches2 = matches3 = 0;
/* parse command line and check usage */
while((i = getopt(argc,argv,"M:m:nV")) != EOF) {
switch(i) {
case 'M':
if (m_flag) err_flag++;
M_flag++;
path = optarg;
break;
case 'm':
if (M_flag) err_flag++;
m_flag++;
path = optarg;
break;
case 'n':
n_flag++;
break;
case 'V':
V_flag++;
break;
default:
err_flag++;
}
}
if (argc-optind < 1) err_flag++;
if (err_flag || V_flag) {
fprintf(stderr,"%s version %s by Devin Reade\n",
basename(argv[0]),versionstr);
}
if (err_flag) {
fprintf(stderr,
"Usage: %s [[-M path] | [-m path]] [-nV] keyword [keyword ...]\n",
basename(argv[0]));
return 1;
}
/* do the search */
if (M_flag) {
manpath = path;
} else {
manpath = getManpath();
}
matches1 = apropos(argc-optind, &argv[optind], WHATIS_MODE);
if (!M_flag) free(manpath);
if (m_flag) {
manpath = path;
matches2 = apropos(argc-optind, &argv[optind], WHATIS_MODE);
}
if (!n_flag) {
matches3 = apropos(argc-optind, &argv[optind], ORCA_W_MODE);
}
i = 0;
if (matches1>0) i+= matches1;
if ( m_flag && matches2>0) i+=matches2;
if (!n_flag && matches3>0) i+=matches3;
if (i==0) {
fprintf(stderr,"%s: %s\n",basename(argv[0]),nothing);
}
#ifdef STACK_CHECK
fprintf(stderr,"stack usage: %d bytes\n",end_stack_check());
#endif
if ((matches1>=0) && (matches2>=0) && (matches3>=0) && i>0) return 0;
return 1;
}

View File

@ -1,18 +0,0 @@
This archive contains the utilities msort(1) and dsort(1). Both sort
text files lexicographically.
Msort is a fast in-place memory sort.
Dsort is a disk based sort that can handle "arbitrarily large" files
(in reality, limited to ULONG_MAX -- 4 294 967 295 -- bytes).
The big difference between these sorts and the previously available
sort(1) is that these won't crash your system ... if either run into
problems, they exit gracefully and (if you are using the verbose flag)
tell you what the problem is.
Enjoy.
Devin Reade
14 June 1994

View File

@ -1,57 +0,0 @@
#include <sys/types.h>
#include <stdio.h>
#ifdef DEFFUNC
# define EXTERN
#else
# define EXTERN extern
#endif
#define ALN2I 1.442695022 /* 1 / ln(2) */
#define TINY 1.0e-5 /* "zero" for heapsort */
#define BUFFERSIZE 4096 /* a generic buffer for I/O */
#define DEFAULT_LINECOUNT 1000 /* number of lines to memory sort */
#define DEFAULT_LINELENGTH 512 /* max length of line recognised */
#define DELIM 0x03 /* ETX */
#ifdef __ORCAC__
# define NEWLINE '\r'
#else
# define NEWLINE '\n'
# define BROKEN_REALLOC
#endif
#ifdef __GNUC__
int printf(char *format, ...);
int fprintf(FILE *stream, char *format, ...);
void perror(char *s);
int close(int fd);
int fclose(FILE *stream);
int rename(char *, char *);
void rewind(FILE *);
#endif
#ifdef DEBUG
# define STATUS(string) fprintf(stderr,"%s\n",string)
extern void begin_stack_check(void);
extern int end_stack_check(void);
#else
# define STATUS(string) {;}
#endif
unsigned long int linecount (char *filename, size_t *maxlinelen);
char **loadarray (unsigned long n, char *filename, size_t maxlinelen);
void sortarray(char *array[], unsigned long n);
int disksort (char *filename, size_t linecount, size_t linelength);
int initdisksort(void);
int mergeone(FILE *fpA, FILE *fpB, FILE *fpC, char strA[], char strB[],
size_t linelength);
EXTERN short v_flag;
EXTERN FILE *out_fp;
#ifdef DSORT
EXTERN FILE *fp1, *fp2, *fp3, *fp4;
EXTERN char *file1, *file2, *file3, *file4;
EXTERN char *tpath1, *tpath2, *tpath3, *tpath4;
#endif

View File

@ -1,262 +0,0 @@
#ifdef __CCFRONT__
#include <14:pragma.h>
#endif
#define DSORT
#include "common.h"
#include <stdlib.h>
#include <unistd.h>
#define KILLTEMP fclose(fp1); fclose(fp2); fclose(fp3); fclose(fp4); \
unlink(file1); unlink(file2); unlink(file3); unlink(file4); \
free(file1); free(file2); free(file3); free(file4)
#define KILLARRAY(a,i) { \
size_t j; \
for (j=0;j<i;j++) free(a[j]); \
free(a); \
}
static char *errmsg1 =
"disksort: write failed on fp1 during construction phase";
static char *errmsg2 =
"disksort: write failed on fp2 during construction phase";
static char *errmsg3 = "disksort: couldn't allocate scratch buffers";
static char *errmsg4 = "disksort: couldn't reopen temp files";
static char *errmsg5 = "disksort: read on temp file failed";
/*
* int disksort (char *infile, size_t linecount, size_t linelength);
*
* Pre: <infile> is the name of the input file. <linecount> is the
* maximum number of text lines we should try to sort in _memory_
* at any one time. If it is zero, then DEFAULT_LINECOUNT is used.
* <linecount> may be much smaller than the actual linecount of
* <infile>. <linelength> - 1 is the maximum length of line from
* <infile> that disksort will recognise. If <linelength> is zero,
* then DEFAULT_LINELENGTH is used. Global out_fp is an open stream.
*
* Post: The file refered to by <infile> is sorted lexicographically
* by lines. If a line is longer than <linelength>, then any extra
* characters in that line will be truncated. On success, disksort
* returns zero. On failure, disksort returns -1. The sorted output
* is printed to out_fp, and <infile> is unchanged.
*
* Note: This routine is based on a polyphase merge sort using four
* temporary files.
*
* Uses Globals:
* fp1, fp2, fp3, fp4, file1, file2, file3, file4, out_fp
*/
int disksort (char *infile, size_t linecount, size_t linelength) {
FILE *in_fp; /* input file pointer */
char lastfile; /* to where did we last write? */
size_t runcount; /* how many runs make up infile? */
FILE *fpA, *fpB, *fpC, *fpD;
char *tempout; /* the name of the final temp file */
char **array;
size_t i;
char *strA, *strB;
/*
*
* PHASE ZERO: Initialization
*
*/
if (initdisksort() != 0) return -1; /* already printed error msgs */
/*
* Open the input file for reading
*/
if ((in_fp=fopen(infile,"r"))==NULL) {
if (v_flag) perror("disksort: couldn't open input file");
KILLTEMP;
return -1;
}
/*
* Get the size of the array of strings we will sort, and create it
*/
if (linecount == 0) linecount = DEFAULT_LINECOUNT;
if (linelength == 0) linelength = DEFAULT_LINELENGTH;
if ((array = malloc (linecount * sizeof(char *))) == NULL) {
if (v_flag) perror("disksort: couldn't allocate array");
fclose(in_fp);
KILLTEMP;
return -1;
}
for (i = 0; i<linecount; i++) {
if ((array[i] = malloc (linelength * sizeof(char))) == NULL) {
if (v_flag) perror("disksort: couldn't allocate array elements");
KILLARRAY(array,i);
fclose(in_fp);
KILLTEMP;
return -1;
}
}
/*
* PHASE I:
*
* Read runs from input file, sort each run, dump to first two
* temp files, alternating between file1 & file2.
*/
lastfile = 'B';
runcount = 0;
while(!feof(in_fp)) {
/* read in a block that can be sorted in core memory */
for (i=0; i<linecount; i++) {
if (fgets(array[i],linelength,in_fp)==NULL) {
if (feof(in_fp)) {
array[i][0] = '\0'; /* end of file */
--i; /* reduce it by one so that sortarray() works */
break;
} else {
if (v_flag) perror(errmsg5); /* file error */
KILLARRAY(array,linecount);
fclose(in_fp);
KILLTEMP;
return -1;
}
}
}
/* sort it */
sortarray(array,i);
/* print it out to one of the temp files and add the end-of-line DELIM */
if (lastfile == 'B') {
for (i=0; (i<linecount) && (array[i][0]!='\0'); i++)
if ((fprintf(fp1,"%s",array[i])==EOF) && v_flag) perror(errmsg1);
lastfile = 'A';
if ((fprintf(fp1,"%c\n",DELIM)==EOF) && v_flag) perror(errmsg1);
} else { /* lastfile == 'A' */
for (i=0; (i<linecount) && (array[i][0]!='\0'); i++)
if ((fprintf(fp2,"%s",array[i])==EOF) && v_flag) perror(errmsg2);
lastfile = 'B';
if ((fprintf(fp2,"%c\n",DELIM)==EOF) && v_flag) perror(errmsg2);
}
}
/* clean up Phase I */
fclose(in_fp);
rewind(fp1);
rewind(fp2);
/*
* merge the files -- at this point, files fp1 and fp2 contain
* multiple runs of <linecount> records. Keep merging and
*/
/* initialize this backwards because of the initial flip */
fpA = fp2;
/* get some scratch strings for the merge */
if (((strA=malloc(linelength))==NULL) ||
((strB=malloc(linelength))==NULL)) {
if (v_flag) perror(errmsg3);
return -1;
}
do {
runcount = 0;
/* flip the files so we can sort back the other way */
if (fpA == fp1) {
fpA = fp3;
fpB = fp4;
fp1 = freopen(file1,"w+",fp1);
fp2 = freopen(file2,"w+",fp2);
if ((fp1==NULL) || (fp2==NULL)) {
if (v_flag) perror(errmsg4);
return -1;
}
fpC = fp1;
fpD = fp2;
} else {
fpA = fp1;
fpB = fp2;
fp3 = freopen(file3,"w+",fp3);
fp4 = freopen(file4,"w+",fp4);
if ((fp3==NULL) || (fp4==NULL)) {
if (v_flag) perror(errmsg4);
return -1;
}
fpC = fp3;
fpD = fp4;
}
rewind(fpA);
rewind(fpB);
/*
* Sort pairs of runs until EOF is reached
*/
for (;;) {
int mergeresult;
/*
* merge one run from each of fpA and fpB into fpC, then repeat
* it but placing the result into fpD.
*/
mergeresult = mergeone(fpA,fpB,fpC,strA,strB,linelength);
if (mergeresult == 0) {
runcount++;
mergeresult = mergeone(fpA,fpB,fpD,strA,strB,linelength);
if (mergeresult == 0) runcount++;
}
if (mergeresult == -1) {
/* both files at EOF */
break;
} else if (mergeresult == -2) {
/* files in error; message already printed */
KILLARRAY(array,linecount);
KILLTEMP;
return -1;
}
/* else normal merge; continue */
}
} while (runcount>1);
/*
* At this point, fpC contains the sorted file. (We hope ...)
*/
if (fpC==fp1) tempout = file1;
else if (fpC==fp2) tempout = file2;
else if (fpC==fp3) tempout = file3;
else /* fpC==fp4 */ tempout = file4;
/*
* clean up and exit
*/
/* copy lines from fpC to infile except for the trailing DELIM */
rewind(fpC);
for (;;) {
if (fgets(strA,linelength,fpC)==NULL) {
if(v_flag) perror(errmsg5);
return -1;
}
if ((strA[0]==DELIM) && (strA[1]=='\n')) break;
if (fprintf(out_fp,"%s",strA)==EOF) {
if (v_flag) perror("disksort: write on output file failed");
return -1;
}
}
free(strA);
free(strB);
KILLARRAY(array,linecount);
KILLTEMP;
return 0;
}

View File

@ -1,130 +0,0 @@
.TH DSORT 1 "Commands and Applications" "14 June 1994" "Version 1.0"
.SH NAME
dsort, msort \- sort text files lexicographically
.SH SYNOPSIS
.B msort
[
.I -hvV?
] [
.I "-o outfile"
] [
.I "-n lines"
]
.I file1
[
.I "file2 ..."
]
.LP
.B dsort
[
.I -hvV?
] [
.I "-l length"
] [
.I "-n lines"
] [
.I "-o outfile"
] [\fI-t path1\fR[,\fIpath2\fR[,\fIpath3\fR[,\fIpath4\fR]]]] \fIinfile\fR
.SH DESCRIPTION
.BR dsort " and " msort
are robust text file sorting utilities. While they do not support a lot
of features, they are designed to sort large (and small) files very quickly.
.LP
.B msort
is an in-place memory sort. Since it uses the heapsort algorithm, it is
O[n lg n] both on average and for worst-case. Provided it has enough memory,
.BR msort
will sort files with lines of arbitrary length. Unless overridden by the
.I -n
flag,
.BR msort
will sort files of up to 1000 lines. Larger files can be sorted provided
there is sufficient core memory. If multiple input files are given, the
output is the concatenated result of sorting the input files separately.
Thus, the following would be equivalent:
.LP
.nf
% msort file1 file2 file3 >outfile
and
% msort file1 >file1out
% msort file2 >file2out
% cat file1out file2out >outfile
.fi
.LP
.B dsort
is a disk sort intended for files too large to be sorted in memory. It
uses a four-file polyphase merge algorithm. Since it is an I/O-bound
program,
.BR dsort "'s
speed is very dependant on the speed of the device used for temporary files.
By default,
.BR dsort
will sort files with lines up to 512 characters long. Lines with more
characters will be trucated unless the
.I -l
flag is used. Also by default, 1000 lines at a time will be sorted in
memory during the collection (first) phase of the merge sort algorithm.
This can be changed using the
.I -n
flag.
.BR dsort
will accept only one input file.
.LP
Both
.BR dsort " and " msort
leave the input file(s) intact.
.SH OPTIONS
.nf
\fI-h\fR \fI-?\fR -- print version and usage info, then exit
\fI-l\fR \fIlength\fR -- use a line length of \fIlength\fR
\fI-n\fR \fIlines\fR -- sort \fIlines\fR lines in memory, (for \fBdsort\fR); don't
try to sort files over \fIlines\fR long (for \fBmsort\fR).
\fI-o\fR \fIoutfile\fR -- send sorted output to \fIoutfile\fR rather than to stdout
\fI-t\fR \fIpathlist\fR -- use \fIpathlist\fR as the locations of temp files. If any
of these are not specified, dsort will attempt to use
the directory specified by the environment variable
$(TMPDIR), then the system default temp path.
\fI-v\fR -- verbose operation
\fI-V\fR -- print version information
.fi
.SH HINTS
If you have more than one fast drive, the speed of
.B dsort
can in general be improved by using four different drives for the
path list when using
.I -t .
The best speed observed, however, has occurred when $(TMPDIR) or /tmp
reside on a RAM disk or ROM disk.
It is not suggested that floppies be used for temporary files.
.SH RESOURCE USAGE
Both
.BR dsort " and " msort
use 1k of stack space.
.LP
.BR msort
is an in-place sort, so in general the amount of core memory used is
the same as the size of the file to be sorted. When sorting multiple
files,
.BR msort "'s
memory usage will match the size of the largest input file, not the
total of all files. It will use a minimum of approximately 4k of core
memory.
.LP
.BR dsort
by default uses approximately 512k of core memory. This can be modified
by changing the
.I -l
and
.I -n
parameters. Core memory usage is approximately the product of these two
parameters.
.LP
When using
.BR dsort ,
the amount free space on the temporary path(s) must be at least twice
the size of the file to be sorted.
.SH AUTHOR
Devin Reade \- glyn@cs.ualberta.ca
.SH SEE ALSO
.BR sort (1),
.BR uniq (1).

View File

@ -1,207 +0,0 @@
#ifdef __CCFRONT__
#include <14:pragma.h>
#endif
/*
* dsort -- sort a text file on disk lexicographically
*
* Synopsis:
* dsort [-hvV?] [-l length] [-n lines] [-o outfile]
* [-t path1[,path2[,path3[,path4]]]] infile
*
* Options:
* -h -? -- print version and usage info, then exit
* -l <length> -- use a line length of <length>
* -n <m> -- sort <m> lines in memory.
* -o <outfile> -- sorted output to <outfile> rather than
* to stdout
* -t <pathlist> -- use <pathlist> (up to four paths) as the locations
* of temp files. <pathlist> is of the form:
* path1[,path2[,path3[,path4]]]. If any of these
* are not specified, dsort will attempt to use
* the system default temp path.
* -v -- verbose operation
* -V -- print version information
*/
#define DEFFUNC
#define DSORT
#include "common.h"
#include <errno.h>
#include <stdlib.h>
#include <string.h>
#include "/usr/include/getopt.h" /* GNU version */
extern int optind;
extern char *optarg;
extern int errno;
static char *versionstring="\
Version 1.0 by Devin Reade\n";
static char *usagestring="\
dsort -- Sort a text file on disk lexicographically\n\
\n\
Synopsis:\n\
\tdsort\t[-hvV?] [-l length] [-n lines] [-o outfile]\n\
\t\t[-t path1[,path2[,path3[,path4]]]] infile\n\
\n\
Options:\n\
\t-h -?\t\t-- Print version and usage info, then exit.\n\
\t-l <length>\t-- Set the maximum line length to <length>.\n\
\t-n <m>\t\t-- Set the number of lines to sort in memory to <m>.\n\
\t-o <outfile>\t-- Dump sorted output to <outfile> rather\n\
\t\t\t than to stdout.\n\
\t-t <pathlist>\t-- Set the paths to use for the location of\n\
\t\t\t scratch files. Paths are delimited by \',\' characters.\n\
\t-v\t\t-- Verbose operation.\n\
\t-V\t\t-- Print version information.\n";
int main (int argc, char **argv) {
size_t lc, i;
char *outfile; /* the name of the output file, if nec */
char **array; /* an array of strings; for sorting */
size_t maxlinelen; /* length of longest line in current file */
size_t maxlinecount; /* max number of lines we want to allow */
char *tbuffer; /* buffer containing the temp paths */
short failed=0; /* any errors found? */
int c;
short errflag=0;
short l_flag=0;
short n_flag=0;
short o_flag=0;
short t_flag=0;
short V_flag=0;
/* v_flag defined in common.h */
#ifdef DEBUG
begin_stack_check();
#endif
/*
* parse the command line
*/
while ((c= getopt(argc,argv,"hl:n:o:t:vV?")) != EOF)
switch (c) {
case 'l': /* use this as the maximum line length */
l_flag++;
errno = 0;
maxlinelen = (size_t) atol(optarg);
if (errno = ERANGE) maxlinelen = DEFAULT_LINELENGTH;
break;
case 'n': /* sort this number of lines in memory */
n_flag++;
errno = 0;
maxlinecount = (size_t) atol(optarg);
if (errno == ERANGE) maxlinecount = DEFAULT_LINECOUNT;
break;
case 'o': /* redirect sorted output to file */
o_flag++;
outfile = optarg;
break;
case 't': /* define locations of temp files */
t_flag++;
if ((tbuffer=malloc(strlen(optarg)+1))==NULL) {
perror("couldn't allocate temporary buffer; using default");
break;
}
strcpy(tbuffer,optarg);
break;
case 'v': /* verbose */
v_flag++;
break;
case 'V': /* print version information */
V_flag++;
break;
case '?': /* fallthrough */
case 'h': /* fallthrough */
default: /* Display usage, version, and exit */
V_flag++;
errflag++;
break;
}
/*
* React to command line parameters
*/
if (errflag) {
fprintf (stderr,"\n%s\n%s\n",usagestring,versionstring);
return -1;
}
if (V_flag) fprintf(stderr,"\n%s\n",versionstring);
if (!l_flag) maxlinelen = DEFAULT_LINELENGTH;
if (!n_flag) maxlinecount = DEFAULT_LINECOUNT;
if (v_flag) fprintf(stderr,
"Sorting %lu lines in memory.\nMaximum recognised line length = %lu\n",
maxlinecount,maxlinelen);
if (o_flag) {
if ((out_fp = fopen(outfile,"w")) == NULL) {
if (v_flag) perror("open on output file failed");
return -1;
}
} else out_fp = stdout;
tpath1 = NULL;
tpath2 = NULL;
tpath3 = NULL;
tpath4 = NULL;
if ((t_flag) && (tbuffer!=NULL)) {
char *tp = tbuffer;
/* set tpath1 */
tpath1 = tp;
while (*tp && (*tp!=',')) tp++;
if (*tp) {
*tp++ = '\0'; /* terminate tpath1 */
if (v_flag) fprintf(stderr,"Will try to use temp directory %s\n",tpath1);
/* set tpath2 */
tpath2 = tp;
while (*tp && (*tp!=',')) tp++;
if (*tp) {
*tp++ = '\0'; /* terminate tpath2 */
if (v_flag)
fprintf(stderr,"Will try to use temp directory %s\n",tpath2);
/* set tpath3 */
tpath3 = tp;
while (*tp && (*tp!=',')) tp++;
if (*tp) {
*tp++ = '\0'; /* terminate tpath3 */
if (v_flag)
fprintf(stderr,"Will try to use temp directory %s\n",tpath3);
/* set tpath4 */
tpath4 = tp;
while (*tp && (*tp!=',')) tp++;
*tp = '\0'; /* terminate tpath4 */
if (v_flag)
fprintf(stderr,"Will try to use temp directory %s\n",tpath4);
}
}
}
} else if (v_flag) fprintf(stderr,"Using default temp path\n");
/* do the sort */
if (argc - optind == 1) {
c = disksort(argv[optind],maxlinecount,maxlinelen);
} else {
fprintf(stderr,"\n%s\n%s\n",usagestring,versionstring);
c = -1;
}
if (t_flag && (tbuffer)) free(tbuffer);
#ifdef DEBUG
fprintf(stderr,"%s stack usage: %d bytes\n",argv[0],end_stack_check());
#endif
return c;
}

View File

@ -1,105 +0,0 @@
#ifdef __CCFRONT__
#include <14:pragma.h>
#endif
#define DSORT
#include "common.h"
#include <stdlib.h>
#include <unistd.h>
#define OPENMODE "w+" /* the mode for create/read/write */
static char *errstring1="initdisksort: couldn't get temp name";
static char *errstring2="initdisksort: couldn't open temp file";
/*
* int initdisksort(void);
*
* Pre: None.
*
* Post: Returns 0 on success, -1 on failure.
* On success:
* file1 through file4 are initialized as temp file names.
* fp1 through fp4 are open file pointers for file1 ... file4.
*
* Uses Globals:
* fp1, fp2, fp3, fp4
* file1, file2, file3, file4,
* v_flag
*/
int initdisksort(void) {
/*
* Get the names for the temp files -- this is ponderous but necessary
*/
if ((file1 = tempnam(tpath1,"dsort")) == NULL) {
if (v_flag) perror(errstring1);
return -1;
}
if ((file2 = tempnam(tpath2,"dsort")) == NULL) {
if (v_flag) perror(errstring1);
free(file1);
return -1;
}
if ((file3 = tempnam(tpath3,"dsort")) == NULL) {
if (v_flag) perror(errstring1);
free(file1);
free(file2);
return -1;
}
if ((file4 = tempnam(tpath4,"dsort")) == NULL) {
if (v_flag) perror(errstring1);
free(file1);
free(file2);
free(file3);
return -1;
}
/*
* Open the temp files -- again ponderous but necessary
*/
if ((fp1 = fopen(file1,OPENMODE))==NULL) {
if (v_flag) perror(errstring2);
free(file1);
free(file2);
free(file3);
free(file4);
return -1;
}
if ((fp2 = fopen(file2,OPENMODE))==NULL) {
if (v_flag) perror(errstring2);
unlink(file1);
free(file1);
free(file2);
free(file3);
free(file4);
return -1;
}
if ((fp3 = fopen(file3,OPENMODE))==NULL) {
if (v_flag) perror(errstring2);
unlink(file1);
unlink(file2);
free(file1);
free(file2);
free(file3);
free(file4);
return -1;
}
if ((fp4 = fopen(file4,OPENMODE))==NULL) {
if (v_flag) perror(errstring2);
unlink(file1);
unlink(file2);
unlink(file3);
free(file1);
free(file2);
free(file3);
free(file4);
return -1;
}
return 0;
}

View File

@ -1,89 +0,0 @@
#ifdef __CCFRONT__
#include <14:pragma.h>
#endif
#include "common.h"
#include <fcntl.h>
#include <stdlib.h>
#include <unistd.h>
/*
* unsigned long int linecount (char *filename, size_t *maxlinelen);
*
* Pre: <filename> is the name of the file for which we need to know
* the number of lines. The file must be closed.
*
* Post: Returns the number of newline characters in the file. On
* return, the file is again closed and *maxlinelen is the length
* of the longest line in <filename> (length is calculated to
* include the newline character but not the null terminator.
* Returns zero on failure or if there are no newlines.
*
* Uses Globals:
* v_flag
*/
unsigned long int linecount (char *filename, size_t *maxlinelen) {
char *buff; /* the input buffer */
unsigned long result; /* the number of newlines */
int count; /* the number of chars last read */
int fd; /* file descriptor for <filename> */
short done;
int i;
size_t linelen; /* length of current line */
/* init some variables */
done = 0;
result = 0;
*maxlinelen = 0;
linelen = 0;
/* open <filename> for unbuffered I/O */
if ((fd = open(filename,O_RDONLY)) == -1) {
if (v_flag) perror("linecount: couldn't open input file");
return 0lu;
}
/* get an input buffer */
if ((buff = malloc(BUFFERSIZE)) == NULL) {
if (v_flag) perror ("linecount: couldn't allocate buffer");
close(fd);
return 0lu;
}
/* repeatedly fill the buffer and increment the newline count */
while (!done) {
count = read (fd, buff, BUFFERSIZE);
switch (count) {
case -1: /* file error */
if (v_flag) perror ("linecount");
close(fd);
free(buff);
return 0lu;
/* NOTREACHED */
break;
case 0: /* EOF */
done = 1;
break;
default: /* got some info in the buffer */
for (i=0; i<count; i++) {
linelen++;
if (buff[i] == NEWLINE) {
result++;
if (linelen > *maxlinelen) *maxlinelen = linelen;
linelen = 0;
}
}
break;
}
}
/* clean up and return */
close(fd);
free(buff);
return result;
}

View File

@ -1,121 +0,0 @@
#ifdef __CCFRONT__
#include <14:pragma.h>
#endif
#include "common.h"
#include <errno.h>
#include <stdlib.h>
#include <string.h>
/*
* char **loadarray (unsigned long n, char *filename, size_t maxlinelen);
*
* Pre: <filename> is the name of a file containing <n> lines of text,
* the number of lines. The file <filename> must be closed.
* <maxlinelen> is the length of the longest line in <filename>
*
* Post: Returns a pointer to an array of pointers to malloc'd strings,
* where the strings are successive lines from the file <filename>.
* On return <filename> will be closed. If loadarray() fails for
* any reason, it will return NULL.
*
* Warning: The use of realloc() with a NULL pointer for the initial
* allocation may not be portable. If this is not valid for your
* current libraries, then #define BROKEN_REALLOC.
*
* Uses Globals:
* v_flag
*/
char **loadarray (unsigned long n, char *filename, size_t maxlinelen) {
char **result;
unsigned long i,j;
FILE *in_fp;
static char *inbuf=NULL;
static size_t previous_size = 0;
char *p;
#ifndef BROKEN_REALLOC /* realloc() is ANSI-compliant with NULL first arg */
/* reallocate the input buffer if necessary */
if (maxlinelen > previous_size) {
if ((p = realloc(inbuf,maxlinelen+1)) == NULL) {
if (v_flag) perror("loadarray: couldn't (re)allocate input buffer");
return NULL;
}
previous_size = maxlinelen;
inbuf = p;
}
#else /* BROKEN_REALLOC */
/* reallocate the input buffer if necessary */
if (maxlinelen > previous_size) {
if (previous_size == 0) {
if ((p = malloc(maxlinelen+1)) == NULL) {
if (v_flag) perror("loadarray: couldn't allocate input buffer");
return NULL;
}
} else {
if ((p = realloc(inbuf,maxlinelen+1)) == NULL) {
if (v_flag) perror("loadarray: couldn't reallocate input buffer");
return NULL;
}
}
previous_size = maxlinelen;
inbuf = p;
}
#endif /* BROKEN_REALLOC */
/* allocate the array */
if ((result = malloc (n * sizeof(char *)))==NULL) {
if (v_flag) perror("loadarray: couldn't allocate base array");
return NULL;
}
/* set up the input stream */
in_fp = fopen(filename,"r");
if (in_fp == NULL) { /* open failed */
free(result);
if (v_flag) perror("loadarray: couldn't open input file");
return NULL;
}
/* allocate and copy elements */
for (i=0; i<n; i++) {
/* read into the buffer */
if(fgets(inbuf,maxlinelen+1,in_fp)==NULL) {
/* read failed; clean up and exit */
if (v_flag) {
if (ferror(in_fp)) perror("loadarray: read error on input file");
else perror ("loadarray: premature EOF on input file");
}
for (j=0; j<i; j++) free(result[j]);
free(result);
fclose(in_fp);
return NULL;
}
/* copy the buffer to the array */
result[i] = malloc(strlen(inbuf)+1);
if (result[i]==NULL) {
/* malloc failed; clean up and exit */
if (v_flag) perror("loadarray: couldn't duplicate buffer");
for (j=0; j<i; j++) free(result[j]);
free(result);
fclose(in_fp);
return NULL;
}
strcpy(result[i],inbuf);
}
fclose(in_fp);
return result;
}

View File

@ -1,55 +0,0 @@
BINDIR = /usr/local/bin
MANDIR = /usr/man
# Nothing should need to be changed below this point
# DEFINES = -DDEBUG -D__GNO__
DEFINES = -D__GNO__
CFLAGS = $(DEFINES) -O -v -w -r
CFLAGS2 = $(DEFINES) -O31 -v -w -r
MAINFLAGS = $(DEFINES) -O -v -w -S1024
LDFLAGS = -v
# LDLIBS = -l/usr/lib/gnulib -l/usr/lib/stack
LDLIBS = -l/usr/lib/gnulib
MOBJS = msort.o linecount.o loadarray.o
DOBJS = dsort.o disksort.o initdisksort.o mergeone.o tempnam.o
COMMONOBJS = sortarray.o
install:
/bin/cp msort dsort $(BINDIR)
/bin/cp msort.1 dsort.1 $(MANDIR)/man1
all: msort dsort
msort : $(MOBJS) $(COMMONOBJS)
$(CC) $(LDFLAGS) $(LDLIBS) -o $@ $<
dsort : $(DOBJS) $(COMMONOBJS)
$(CC) $(LDFLAGS) $(LDLIBS) -o $@ $<
msort.o: msort.c common.h
$(CC) -c $(MAINFLAGS) -o $@ msort.c
dsort.o: dsort.c common.h
$(CC) -c $(MAINFLAGS) -o $@ dsort.c
# Orca/C screws up with loop invariant optimization on disksort.c
disksort.o: disksort.c common.h
$(CC) -c $(CFLAGS2) -o $@ disksort.c
#
# Housekeeping
#
clean:
$(RM) $(DOBJS) $(MOBJS) $(COMMONOBJS) msort.root dsort.root
clobber: clean
$(RM) dsort msort
#
# Additional dependencies
#
linecount.o loadarray.o initdisksort.o mergeone.o sortarray.o:: common.h

View File

@ -1,169 +0,0 @@
#ifdef __CCFRONT__
#include <14:pragma.h>
#endif
#define DSORT
#include "common.h"
#include <string.h>
/*
* int mergeone(FILE *fpA, FILE *fpB, FILE *fpC, char strA[], char strB[],
* size_t linelength);
*
* Pre: fpA, fpB, and fpC are open file pointers. The first should contain
* "runs" of data delimited by a line consisting of just the DELIM
* character, although either or both may be at EOF. strA and strB
* are scratch character buffers, each of size linelength.
*
* Post: The first run on each of fpA and fpB are merge-sorted and added to
* fpC. If either fpA or fpB are at EOF then the run from the other
* file pointer is simply concatenated onto fpC. Mergeone will return
* zero if the merge was successful, -1 if both fpA and fpB are at
* EOF, and -2 if there was an error. On return, the contents of
* strA and strB are undefined.
*
* Uses Globals:
* v_flag -- if set and an error occurs, a message will be printed
* to stderr
* fp1,fp2,fp3,fp4 -- file pointers to the four scratch files
* file1,file2,file3,file4 -- names of the four scratch files
*/
int mergeone(FILE *fpA, FILE *fpB, FILE *fpC, char strA[], char strB[],
size_t linelength) {
short run_end_A = 0;
short run_end_B = 0;
/*
* Load strA and strB with the first lines from fpA and fpB. After
* this, either file may be at EOF (but not error).
*/
if ((fgets(strA,linelength,fpA)==NULL) && ferror(fpA)) {
if (v_flag) perror("mergeone: Read error on fpA");
return -2;
}
if ((fgets(strB,linelength,fpB)==NULL) && ferror(fpB)) {
if (v_flag) perror("mergeone: Read error on fpB");
return -2;
}
/*
* merge fpA and fpB until we either get an EOF or a DELIM line
*/
while (!feof(fpA) && !feof(fpB)) {
/* test to see if our run is finished */
if ((strA[0]==DELIM) && (strA[1]=='\n')) {
run_end_A = 1;
break;
}
if ((strB[0]==DELIM) && (strB[1]=='\n')) {
run_end_B = 1;
break;
}
if (strcmp(strA,strB) < 0) {
/* print out the string to fpC */
if (fprintf(fpC,"%s",strA) == EOF) {
if (v_flag) perror("mergeone: Write error on fpC");
return -2;
}
/* get another string from fpA */
if ((fgets(strA,linelength,fpA)==NULL) && ferror(fpA)) {
if (v_flag) perror("mergeone: Read error on fpA");
return -2;
}
} else {
/* print out the string to fpC */
if (fprintf(fpC,"%s",strB) == EOF) {
if (v_flag) perror("mergeone: Write error on fpC");
return -2;
if (v_flag) {
/* say something */
}
return -2;
}
/* get another string from fpB */
if ((fgets(strB,linelength,fpB)==NULL) && ferror(fpB)) {
if (v_flag) perror("mergeone: Read error on fpB");
return -2;
}
}
}
/*
* We've come to the end of at least one of the runs, concatenate
* the remainder on the output file
*/
/* finish off fpA if necessary */
while (!run_end_A && !feof(fpA)) {
/* test to see if our run is finished */
if ((strA[0]==DELIM) && (strA[1]=='\n')) {
run_end_A = 1;
break;
}
/* print out the string to fpC */
if (fprintf(fpC,"%s",strA) == EOF) {
if (v_flag) perror("mergeone: Write error on fpC");
return -2;
}
/* get another string from fpA */
if ((fgets(strA,linelength,fpA)==NULL) && ferror(fpA)) {
if (v_flag) perror("mergeone: Read error on fpA");
return -2;
}
}
/* finish off fpB if necessary */
while (!run_end_B && !feof(fpB)) {
/* test to see if our run is finished */
if ((strB[0]==DELIM) && (strB[1]=='\n')) {
run_end_B = 1;
break;
}
/* print out the string to fpC */
if (fprintf(fpC,"%s",strB) == EOF) {
if (v_flag) perror("mergeone: Write error on fpC");
return -2;
}
/* get another string from fpB */
if ((fgets(strB,linelength,fpB)==NULL) && ferror(fpB)) {
if (v_flag) perror("mergeone: Read error on fpB");
return -2;
}
}
/*
* At this point, both fpA and fpB are either at a run-end or at EOF,
* with no errors. If at EOF, then don't append a DELIM character.
*/
if (feof(fpA) && feof(fpB)) return -1;
if (fprintf(fpC,"%c\n",DELIM) == EOF) {
if (v_flag) perror("mergeone: Write error on fpC");
return -2;
}
return 0;
}

View File

@ -1 +0,0 @@
.so /usr/man/man1/dsort.1

View File

@ -1,155 +0,0 @@
#ifdef __CCFRONT__
#include <14:pragma.h>
#endif
/*
* msort -- sort a text file in memory lexicographically
*
* Synopsis:
* msort [-hvV?] [-o outfile] [-n lines] file1 [file2 ...]
*
* Options:
* -h -? -- print version and usage info, then exit
* -n <lines> -- don't try to sort files over <lines> lines long
* -o <outfile> -- sorted output to <outfile> rather than
* to stdout
* -v -- verbose operation
* -V -- print version information
*/
#define DEFFUNC
#define MSORT
#include "common.h"
#include <limits.h>
#include <stdlib.h>
#include <errno.h>
#include "/usr/include/getopt.h" /* GNU version */
extern int optind;
extern char *optarg;
extern int errno;
static char *versionstring="\
Version 1.0 by Devin Reade\n";
static char *usagestring="\
msort -- Sort a text file in memory lexicographically\n\
\n\
Synopsis:\n\
\tmsort [-hvV?] [-o outfile] file1 [file2 ...]\n\
\n\
Options:\n\
\t-h -?\t\t-- Print version and usage info, then exit.\n\
\t-n <m>\t\t-- Set the maximum number of lines per file to <m>.\n\
\t-o <outfile>\t-- Dump sorted output to <outfile> rather\n\
\t\t\t than to stdout.\n\
\t-v\t\t-- Verbose operation.\n\
\t-V\t\t-- Print version information.\n";
int main (int argc, char **argv) {
size_t lc, i;
char *outfile; /* the name of the output file, if nec */
char **array; /* an array of strings; for sorting */
size_t maxlinelen; /* length of longest line in current file */
size_t maxlinecount; /* max number of lines we want to allow */
short failed=0; /* any errors found? */
int c;
short errflag=0;
short n_flag=0;
short o_flag=0;
short V_flag=0;
/* v_flag defined in common.h */
#ifdef DEBUG
begin_stack_check();
#endif
/*
* parse the command line
*/
while ((c= getopt(argc,argv,"hn:o:vV?")) != EOF)
switch (c) {
case 'n': /* don't try to sort if file is over n lines long */
n_flag++;
errno = 0;
maxlinecount = (size_t) atol(optarg);
if (errno == ERANGE) maxlinecount = DEFAULT_LINECOUNT;
break;
case 'o': /* redirect sorted output to file */
o_flag++;
outfile = optarg;
break;
case 'v': /* verbose */
v_flag++;
break;
case 'V': /* print version information */
V_flag++;
break;
case '?': /* fallthrough */
case 'h': /* fallthrough */
default: /* Display usage, version, and exit */
V_flag++;
errflag++;
break;
}
/*
* React to command line parameters
*/
if (errflag) {
fprintf(stderr,"\n%s\n%s\n",usagestring,versionstring);
return -1;
}
if (V_flag) fprintf(stderr,"\n%s\n",versionstring);
if (!n_flag) maxlinecount = DEFAULT_LINECOUNT;
if (v_flag) fprintf(stderr,"Maximum lines per file = %lu\n",maxlinecount);
if (o_flag) {
if ((out_fp = fopen(outfile,"w")) == NULL) {
if (v_flag) perror("open on output file failed");
return -1;
}
} else out_fp = stdout;
/* loop through files */
for (; optind<argc; optind++) {
/* get the line count */
lc = linecount(argv[optind], &maxlinelen);
if (lc>maxlinecount) {
if (v_flag)
fprintf(stderr,"%s too long for an in-memory sort -- file skipped\n",
argv[optind]);
failed = 1;
continue;
}
/* load the array */
array = loadarray (lc, argv[optind], maxlinelen);
if (array == NULL) {
if (v_flag) fprintf(stderr,"Ignoring file %s\n",argv[optind]);
failed = 1;
continue;
}
/* sort it */
sortarray (array,lc);
/* print the sorted file out and clean up the array */
for (i=0; i<lc; i++) {
fprintf(out_fp,"%s",array[i]);
free(array[i]);
}
free(array);
}
#ifdef DEBUG
fprintf(stderr,"%s stack usage: %d bytes\n",argv[0],end_stack_check());
#endif
if (failed) return -1;
else return 0;
}

View File

@ -1,62 +0,0 @@
#ifdef __CCFRONT__
#include <14:pragma.h>
#endif
#include "common.h"
#include <string.h>
/*
* void sortarray(char **array, unsigned long n);
*
* Pre: <array> is a pointer to an array of pointers to NULL-terminated
* strings, and <n> is the number of elements in <array>
*
* Post: The strings in <array> are sorted lexicographically in ascending
* order, using the heapsort algorithm. This is an in-place
* non-recursive sort with behavior O[n*lg(n)] both on average
* and worst-case.
*/
void sortarray(char *array[], unsigned long n) {
long l, j, ir, i;
char *rra;
if (n==1) return; /* no need to sort one element */
--array; /* fudge since the algorithm was designed */
/* for a unit-indexing */
l = (n>>1) + 1;
ir = n;
/*
* The index l will be decremented from its initial value down to 0 during
* the heap creation phase. Once it reaches 0, the index ir will be
* decremented from its initial value down to 0 during the heap selection
* phase.
*/
for (;;) {
if (l > 1) /* still in creation phase */
rra = array[--l];
else { /* in selection phase */
rra= array[ir]; /* clear a space at the end of array */
array[ir] = array[1]; /* retire the top of the heap into it */
if (--ir == 1) { /* done with the last promotion */
array[1] = rra;
return;
}
}
i = l; /* set up to sift down element rra to its proper place */
j = l << 1;
while (j<=ir) {
if (j<ir && (strcmp(array[j],array[j+1])<0)) ++j;
if (strcmp(rra,array[j])<0) { /* demote rra */
array[i] = array[j];
i = j;
j += i;
} else j = ir + 1; /* this is rra's level; set j to terminate */
} /* the sift-down */
array[i] = rra;
}
}

View File

@ -1,130 +0,0 @@
#ifdef __CCFRONT__
#include <14:pragma.h>
#endif
/*
* #include <stdio.h>
*
* char *tempnam (const char *dir, const char *prefix);
*
* Generate a pathname for a temporary file.
*
* tempnam will select a directory for the temporary file by using the
* following criteria:
*
* If dir is not the NULL pointer, tempnam uses the pathname pointed to by
* dir as the directory,
*
* otherwise, tmpdir uses the value of the TMPDIR environment variable if
* the variable is defined,
*
* otherwise the directory defined by P_tmpdir in the stdio.h header file
* if that directory is writable by the caller,
*
* otherwise, tempnam will use "/tmp" as a last resort.
*/
#ifdef __ORCAC__
#define __GNO__ 1
#endif
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <unistd.h>
#define max(A,B) (((A)<(B))?(B):(A))
#if !defined(__GNO__)
extern char *mktemp();
extern int access();
#endif
static char seed[4]="AAA";
#if (defined __GNO__)
static char pbrk;
#else
# define pbrk '/';
#endif
/* BSD stdio.h doesn't define P_tmpdir, so let's do it here */
#ifndef P_tmpdir
static char *P_tmpdir = "/tmp";
#endif
static char *
cpdir(char *buf, char *str)
{
char *p;
char *path;
if(str != NULL) {
#if defined(__GNO__)
/* get the path delimiter */
if (strchr(str,':')) pbrk = ':';
else if (strchr(str,'/')) pbrk = '/';
else {
if ((path=getenv("PATH"))==NULL) pbrk = '/';
else pbrk = (strchr(path,':')) ? ':' : '/';
}
#endif
(void) strcpy(buf, str);
p = buf - 1 + strlen(buf);
if(*p == pbrk) *p = '\0';
}
return(buf);
}
char *
tempnam (char *dir, char *prefix)
/* dir -- use this directory please (if non-NULL) */
/* prefix -- use this (if non-NULL) as filename prefix */
{
register char *p, *q, *tmpdir;
int tl=0, dl=0, pl;
/* create a buffer <p> that's as large as necessary */
pl = strlen(P_tmpdir);
if( (tmpdir = getenv("TMPDIR")) != NULL ) tl = strlen(tmpdir);
if( dir != NULL ) dl = strlen(dir);
if( (p = malloc((unsigned int)(max(max(dl,tl),pl)+16))) == NULL )
return(NULL);
*p = '\0';
#if defined (__GNO__)
if( (dl == 0) || (access( cpdir(p, dir), W_OK) != 0) )
if( (tl == 0) || (access( cpdir(p, tmpdir), W_OK) != 0) )
if( access( cpdir(p, P_tmpdir), W_OK) != 0 )
if( access( cpdir(p, "/tmp"), W_OK) != 0 )
return(NULL);
#else /* not __GNO__ */
if( (dl == 0) || (access( cpdir(p, dir), 3) != 0) )
if( (tl == 0) || (access( cpdir(p, tmpdir), 3) != 0) )
if( access( cpdir(p, P_tmpdir), 3) != 0 )
if( access( cpdir(p, "/tmp"), 3) != 0 )
return(NULL);
#endif /* not __GNO__ */
(void) strcat(p, "/");
if(prefix)
{
*(p+strlen(p)+5) = '\0';
(void)strncat(p, prefix, 5);
}
(void)strcat(p, seed);
(void)strcat(p, "XXXXXX");
q = seed;
while(*q == 'Z') *q++ = 'A';
++*q;
if(*mktemp(p) == '\0') return(NULL);
return(p);
}

View File

@ -1,62 +0,0 @@
whereis v1.1 (Gno)
============
INSTALLATION
============
If you have Gno and dmake, type "dmake install". Otherwise:
FILE: COPY TO:
Gno: Orca/whereis 17/whereis [if desired]
Gno/whereis /usr/bin/whereis
whereis.1 $(USRMAN)/man1/whereis.1
Orca: Orca/whereis 17/whereis
whereis.cat 17/help/whereis
=====
NOTES
=====
Whereis is VERY dependant on pathnames.
This archive consist of both Orca shell and Gno versions. Both versions
will work with both shells, the difference being that in the Gno version
the leading "31" has been stripped from pathnames. (It is no longer needed
because of namespace.)
I strongly recommend _not_ using the Gno version with the Orca shell unless
you have actual partitions named "/usr", "/bin", "/etc", and so on, as you
will get _many_ accesses to all online devices in this case.
A -V flag and rVersion resource have been added to show version information.
A -c flag has been added to provide case-insensitive searches.
The source is released because it is small, and you can change the pathnames
if you wish.
=======
HISTORY
=======
v1.1: Rewritten to take advantage of Gno 2.x's namespace feature.
Separate Gno and Orca versions created.
Prototyped.
Disabled references to the /man volume (both versions).
Fixed up man page.
Added -V flag to show version information.
Added -c flag to force case-insensitive searches.
Added "17" to list of directories to search for binaries.
Added "17/help" to list of directories to search for man pages.
v1.0: Initial release.
=======
AUTHORS
=======
Author of the original original port from BSD to Gno is unknown. (Jawaid?)
v1.1 updated by G. Devin Reade <glyn@cs.ualberta.ca>

View File

@ -1,39 +0,0 @@
# Makefile.mk generated by makedmake (Gno) v1.1.1 for Dennis Vadura's dmake
BINDIR = 17
MANDIR = /usr/man
# development flags
# DEFINES += -DDEBUG -DCASEFLAG
# CFLAGS += -w -s1023 -G25 $(DEFINES)
# LDFLAGS +=
# LDLIBS = /usr/lib/stack.a
# distribution flags
DEFINES += -DCASEFLAG
CFLAGS += -w -s1023 -O $(DEFINES)
LDFLAGS +=
LDLIBS =
all:
echo Targets ...
echo
echo dmake install ... to copy executable file to $(BINDIR) and manual
echo page to $(MANDIR)
echo
echo dmake whereis ... to compile source code. This should not be
echo necessary.
whereis : whereis.o
$(CC) $(LDFLAGS) -o whereis whereis.o $(LDLIBS)
whereis.o : whereis.c
$(CC) $(CFLAGS) -c whereis.c
install :
-$(RM) /usr/bin/whereis
-$(RM) 17/whereis
/bin/cp -f whereis $(BINDIR)
/bin/cp -f whereis.1 $(MANDIR)/man1
.SILENT: all

View File

@ -1,133 +0,0 @@
.\" @(#)whereis.1 1.17 90/02/15 SMI; from UCB 4.2
.TH WHEREIS 1 "Commands and Applications" "2 January 1994" "Orca/Gno Version 1.1"
.SH NAME
whereis \- locate the binary, source, and manual page files for a command
.SH SYNOPSIS
.B whereis
[
.B \-bcmsuV
] [
.B \-BMS
.IR directory .\|.\|.
.B \-f
]
\fIfilename\fP\|
.SH DESCRIPTION
.B whereis
locates source/binary and manuals sections for specified
files.
The supplied names are first stripped of leading pathname components
and any (single) trailing extension of the form
.BR .ext ,
for example,
.BR .c .
Prefixes of
.B s.
resulting from use of source code control are also dealt with.
.B whereis
then attempts to locate the desired program in
a list of standard places:
.RS
.nf
/bin
/usr/bin
/usr/sbin
/usr/games
/usr/include
/usr/hosts
/usr/local
/usr/local/bin
/etc
/man (disabled)
/usr/man
/usr/src/bin
/usr/src/etc
17/
17/help
.fi
.RE
.SH OPTIONS
.B \-b
Search only for binaries.
.LP
.B \-c
Make the search case\-insensitive.
.LP
.B \-f
Terminate the last directory list and signals the start of file names,
and
.I must
be used when any of the
.BR \-B ,
.BR \-M ,
or
.B \-S
options are used.
.LP
.B \-m
Search only for manual sections.
.LP
.B \-s
Search only for sources.
.LP
.B \-u
Search for unusual entries. A file is said to be unusual if it does
not have one entry of each requested type. Therefore
.B "whereis -m -u *"
asks for those files in the current
directory which have no documentation.
.LP
.B \-B
Change or otherwise limit the places where
.B whereis
searches for binaries.
.LP
.B \-M
Change or otherwise limit the places where
.B whereis
searches for
manual sections.
.LP
.B \-S
Change or otherwise limit the places where
.B whereis
searches for sources.
.LP
.B \-V
Print version information.
.SH EXAMPLE
Find all files in
.B /usr/bin
which are not documented
in
.B /usr/share/man/man1
with source in
.BR /usr/src/cmd :
.RS
.nf
example% cd /usr/ucb
example% whereis \-u \-M /usr/share/man/man1 \-S /usr/src/cmd \-f *
.fi
.RE
.SH FILES
.nf
/usr/src/*
/usr/{doc,man}/*
/usr/{lib,bin,ucb,old,new,local}
/etc
.fi
.SH SEE ALSO
.BR chdir (2V)
.SH BUGS
Since
.B whereis
uses
.BR chdir (2V)
to run faster, pathnames given with the
.BR \-M ,
.BR \-S ,
or
.B \-B
must be full; that is, they must begin with a
.BR / .

View File

@ -1,528 +0,0 @@
#ifdef __CCFRONT__
#include <14:pragma.h>
#endif
/*-
* Copyright (c) 1980 The Regents of the University of California.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* 3. All advertising materials mentioning features or use of this software
* must display the following acknowledgement:
* This product includes software developed by the University of
* California, Berkeley and its contributors.
* 4. Neither the name of the University nor the names of its contributors
* may be used to endorse or promote products derived from this software
* without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*/
#ifndef lint
char copyright[] =
"@(#) Copyright (c) 1980 The Regents of the University of California.\n\
All rights reserved.\n";
#endif /* not lint */
#ifndef lint
static char sccsid[] = "@(#)whereis.c 5.5 (Berkeley) 4/18/91";
#endif /* not lint */
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <sys/param.h>
#include <sys/types.h>
#include <dirent.h>
#include <stdio.h>
#include <ctype.h>
#include <libc.h>
/*
* Pointers that will correspond to the GNO_* or ORCA_* structs, below
*/
static char **bindirs;
static char **mandirs;
static char **srcdirs;
/*
* These are the directories to check when running under the Gno shell
*/
static char *GNO_bindirs[] = {
"/bin",
"/usr/bin",
"/usr/sbin",
"/usr/games",
"/usr/include",
"/usr/hosts",
"/usr/local",
"/usr/local/bin",
"17",
"/etc",
0
};
/* This needs to be redone - man pages live with sources */
static char *GNO_mandirs[] = {
/*
These are disabled since /man is not usually present; this eliminates
a long series of accesses to the 3.5" drive.
"/man/man1",
"/man/man2",
"/man/man3",
"/man/man4",
"/man/man5",
"/man/man6",
"/man/man7",
"/man/man8",
"/man/cat1",
"/man/cat2",
"/man/cat3",
"/man/cat4",
"/man/cat5",
"/man/cat6",
"/man/cat7",
"/man/cat8",
*/
"/usr/man/cat1",
"/usr/man/cat2",
"/usr/man/cat3",
"/usr/man/cat4",
"/usr/man/cat5",
"/usr/man/cat6",
"/usr/man/cat7",
"/usr/man/cat8",
"/usr/man/man1",
"/usr/man/man2",
"/usr/man/man3",
"/usr/man/man4",
"/usr/man/man5",
"/usr/man/man6",
"/usr/man/man7",
"/usr/man/man8",
"17/help",
0
};
static char *GNO_srcdirs[] = {
"/usr/src/bin",
"/usr/src/etc",
/* still need libs */
0
};
/*
* These are the directories to check when running under the Orca shell
*/
static char *ORCA_bindirs[] = {
"31/bin",
"31/usr/bin",
"31/usr/sbin",
"31/usr/games",
"31/usr/include",
"31/usr/hosts",
"31/usr/local",
"31/usr/local/bin",
"17",
"31/etc",
0
};
/* This needs to be redone - man pages live with sources */
static char *ORCA_mandirs[] = {
/*
These are disabled since /man is not usually present; this eliminates
a long series of accesses to the 3.5" drive.
"31/man/man1",
"31/man/man2",
"31/man/man3",
"31/man/man4",
"31/man/man5",
"31/man/man6",
"31/man/man7",
"31/man/man8",
"31/man/cat1",
"31/man/cat2",
"31/man/cat3",
"31/man/cat4",
"31/man/cat5",
"31/man/cat6",
"31/man/cat7",
"31/man/cat8",
*/
"31/usr/man/cat1",
"31/usr/man/cat2",
"31/usr/man/cat3",
"31/usr/man/cat4",
"31/usr/man/cat5",
"31/usr/man/cat6",
"31/usr/man/cat7",
"31/usr/man/cat8",
"31/usr/man/man1",
"31/usr/man/man2",
"31/usr/man/man3",
"31/usr/man/man4",
"31/usr/man/man5",
"31/usr/man/man6",
"31/usr/man/man7",
"31/usr/man/man8",
"17/help",
0
};
static char *ORCA_srcdirs[] = {
"31/usr/src/bin",
"31/usr/src/etc",
/* still need libs */
0
};
#ifdef CASEFLAG
int cflag = 0;
#endif
char sflag = 1;
char bflag = 1;
char mflag = 1;
char **Sflag;
int Scnt;
char **Bflag;
int Bcnt;
char **Mflag;
int Mcnt;
char uflag;
char *verstring = "whereis -- Apple IIgs Version 1.2";
void getlist (int *argcp, char ***argvp, char ***flagp, int *cntp);
void zerof(void);
void lookup (register char *cp);
void looksrc (char *cp);
void lookbin (char *cp);
void lookman (char *cp);
void findv (char **dirv, int dirc, char *cp);
void find (char **dirs, char *cp);
void findin (char *dir, char *cp);
int itsit (register char *cp, register char *dp);
#ifdef DEBUG
void begin_stack_check(void);
int end_stack_check(void);
#endif
/*
* whereis name
* look for source, documentation and binaries
*/
int main(int argc, char **argv)
{
#ifdef DEBUG
begin_stack_check();
#endif
argc--, argv++;
if (argc == 0) {
usage:
#ifdef CASEFLAG
fprintf(stderr, "whereis [ -sbmucV ] [ -SBM dir ... -f ] name...\n");
#else /* not CASEFLAG */
fprintf(stderr, "whereis [ -sbmuV ] [ -SBM dir ... -f ] name...\n");
#endif
#ifdef DEBUG
if (getenv("CHECKSTACK"))
printf("Stack Usage: %d\n",end_stack_check());
#endif
exit(1);
}
/* select which directory structures we're going to use */
if (needsgno()) {
bindirs = GNO_bindirs;
mandirs = GNO_mandirs;
srcdirs = GNO_srcdirs;
} else {
bindirs = ORCA_bindirs;
mandirs = ORCA_mandirs;
srcdirs = ORCA_srcdirs;
}
do
if (argv[0][0] == '-') {
register char *cp = argv[0] + 1;
while (*cp) switch (*cp++) {
case 'f':
break;
case 'S':
getlist(&argc, &argv, &Sflag, &Scnt);
break;
case 'B':
getlist(&argc, &argv, &Bflag, &Bcnt);
break;
case 'M':
getlist(&argc, &argv, &Mflag, &Mcnt);
break;
case 's':
zerof();
sflag++;
continue;
case 'u':
uflag++;
continue;
case 'b':
zerof();
bflag++;
continue;
case 'm':
zerof();
mflag++;
continue;
#ifdef CASEFLAG
case 'c':
cflag++;
continue;
#endif /* not CASEFLAG */
case 'V':
printf("%s\n",verstring);
continue;
default:
goto usage;
}
argv++;
} else
lookup(*argv++);
while (--argc > 0);
#ifdef DEBUG
if (getenv("CHECKSTACK"))
printf("Stack Usage: %d\n",end_stack_check());
#endif
exit(0);
}
void getlist (int *argcp, char ***argvp, char ***flagp, int *cntp) {
(*argvp)++;
*flagp = *argvp;
*cntp = 0;
for ((*argcp)--; *argcp > 0 && (*argvp)[0][0] != '-'; (*argcp)--)
(*cntp)++, (*argvp)++;
(*argcp)++;
(*argvp)--;
}
void zerof (void) {
if (sflag && bflag && mflag)
sflag = bflag = mflag = 0;
}
int count;
int print;
void lookup (register char *cp) {
register char *dp;
for (dp = cp; *dp; dp++)
continue;
for (; dp > cp; dp--) {
if (*dp == '.') {
*dp = 0;
break;
}
}
for (dp = cp; *dp; dp++)
if (*dp == '/')
cp = dp + 1;
if (uflag) {
print = 0;
count = 0;
} else
print = 1;
again:
if (print)
printf("%s:", cp);
if (sflag) {
looksrc(cp);
if (uflag && print == 0 && count != 1) {
print = 1;
goto again;
}
}
count = 0;
if (bflag) {
lookbin(cp);
if (uflag && print == 0 && count != 1) {
print = 1;
goto again;
}
}
count = 0;
if (mflag) {
lookman(cp);
if (uflag && print == 0 && count != 1) {
print = 1;
goto again;
}
}
if (print)
printf("\n");
}
void looksrc (char *cp) {
if (Sflag == 0) {
find(srcdirs, cp);
} else
findv(Sflag, Scnt, cp);
}
void lookbin (char *cp) {
if (Bflag == 0)
find(bindirs, cp);
else
findv(Bflag, Bcnt, cp);
}
void lookman (char *cp) {
if (Mflag == 0) {
find(mandirs, cp);
} else
findv(Mflag, Mcnt, cp);
}
void findv (char **dirv, int dirc, char *cp) {
while (dirc > 0)
findin(*dirv++, cp), dirc--;
}
void find (char **dirs, char *cp) {
while (*dirs)
findin(*dirs++, cp);
}
void findin (char *dir, char *cp) {
DIR *dirp;
struct dirent *dp;
dirp = opendir(dir);
if (dirp == NULL)
return;
while ((dp = readdir(dirp)) != NULL) {
if (itsit(cp, dp->d_name)) {
count++;
if (print)
printf(" %s/%s", dir, dp->d_name);
}
}
closedir(dirp);
}
#ifdef CASEFLAG
int itsit (register char *cp, register char *dp) {
register int i = strlen(dp);
if (cflag) {
if ( (dp[0] == 's' || dp[0] == 'S') && dp[1] == '.' && itsit(cp, dp+2))
return (1);
while (*cp && *dp && (tolower(*cp) == tolower(*dp)))
cp++, dp++, i--;
if (*cp == 0 && *dp == 0)
return (1);
while (isdigit(*dp))
dp++;
if (*cp == 0 && *dp++ == '.') {
--i;
/* removed for GNO/ME, cause we want to look up compressed files also. */
/* while (i > 0 && *dp)
if (--i, *dp++ == '.')
return (*dp++ == 'C' && *dp++ == 0);
*/
return (1);
}
} else {
if (dp[0] == 's' && dp[1] == '.' && itsit(cp, dp+2))
return (1);
while (*cp && *dp && *cp == *dp)
cp++, dp++, i--;
if (*cp == 0 && *dp == 0)
return (1);
while (isdigit(*dp))
dp++;
if (*cp == 0 && *dp++ == '.') {
--i;
/* removed for GNO/ME, cause we want to look up compressed files also. */
/* while (i > 0 && *dp)
if (--i, *dp++ == '.')
return (*dp++ == 'C' && *dp++ == 0);
*/
return (1);
}
}
return (0);
}
#else /* not CASEFLAG */
int itsit (register char *cp, register char *dp) {
register int i = strlen(dp);
if (dp[0] == 's' && dp[1] == '.' && itsit(cp, dp+2))
return (1);
while (*cp && *dp && *cp == *dp)
cp++, dp++, i--;
if (*cp == 0 && *dp == 0)
return (1);
while (isdigit(*dp))
dp++;
if (*cp == 0 && *dp++ == '.') {
--i;
/* removed for GNO/ME, cause we want to look up compressed files also. */
/* while (i > 0 && *dp)
if (--i, *dp++ == '.')
return (*dp++ == 'C' && *dp++ == 0);*/
return (1);
}
return (0);
}
#endif

View File

@ -1,145 +0,0 @@
$Id: README,v 1.3 1996/01/28 17:39:22 gdr Exp $
This is the README file for the describe package. This package is
designated as version 1.0.3, and consists of the following utilities:
describe v1.0.3 - show database entries describing the current
status of programs
descc v1.0.3 - the describe source compiler
descu v1.0.3 - the describe source updater
ABOUT DESCRIBE AND DESCC
========================
This is yet another project I've been sitting on for a while, but have
finally decided to release. The basic idea of the 'describe' package
(the descc "compiler" and describe itself) is to provide a quick, easy
way of accessing information related to the utilities which so many
different people are releasing these days. The reason it sat around on
my harddrive so long is I was having qualms about its designated role in
life. I wasn't sure exactly what I wanted it to do. Well, I've decided
to KISS for now: descc simply compiles the utility list, which I maintain,
into a (very) simple "database" located in /usr/local/lib/
[alternatively, the full path given in the environment variable DESCDB will be
used, if it is set. sb]. The companion utility 'describe' is used to
fetch information about a particular utility from this "database".
descc is fairly limited, as is the "database" format itself. Part of the
KISS (or it wouldn't be out now) design philosophy ;). Usage is simple:
when you get a new listing (I'll provide monthly updates), simply "descc
<filename>" where <filename> is the name of the newly released update.
descc will simply write over the old database and replace it with the
new. (Note: No appendages are allowed by descc. See descu.)
As always, coments are appreciated. And, moreso than on other projects,
I'd appreciate some comments about the direction I'm going in, suggestions
as to where to take this, etc. I have a feeling that some fields in the
format (eg, FTP:) are rather useless, and I'd like to know what you guys
out there think.
James Brookes
jamesb@ecst.csuchico.edu
ABOUT DESCU
===========
I think describe and descc were really good ideas; they sure beat the
text file list of Gno utilities that James used to keep. The one major
shortfall I found was having to manually update the describe database
source every time I wanted to include a new entry.
I therefore wrote descu, the describe updater, which is also rather
limited due to following the KISS principle.
For completeness, I have also added the man pages describe.1, descc.8,
and descu.8. I briefly pondered having a describe.5, but alas I was too
lazy; you can find the file formats as part of descc.8.
Devin Reade
gdr@myrias.ab.ca
INSTALLATION
============
You can either type "dmake install", or do the following:
mkdir -p /usr/local/lib
cp ./describe /usr/local/bin
cp ./descc /usr/sbin
cp ./descu /usr/sbin
rm /usr/local/bin/descc
You will also want to do the following, which is NOT done by dmake's
install target:
rehash
descc ./describe.source
CHANGES
=======
This details changes to the entire distribution.
v1.03 January 1996
descu now sorts entries correctly (longer entries
ended up before shorter ones with 1.0.2, i.e. "calls"
came before "cal")
v1.02 October 1995
descc now circumvents a bug in ORCA/C's ftell() function.
describe can now find entries that are not all lower-case.
describe will now print the name of entries in the case
they were entered into the database.
descu now sorts the describe source file case-insensitive.
describe and descc can now find the database in a path given
by the environment variable DESCDB. If DESCDB is not set,
/usr/local/lib/describe is used, as before.
A new "Shell:" field has been added to the format of the database.
v1.01 May 1995
Initial release for descu.
Added -h and -v flags to describe and descc.
Common defines and typedefs were extracted to desc.h.
Descc now exits -1 on failure (vice 0).
In descc, some more error checking and flushing were added. Also,
mygets wasn't dereferencing one of its arguments properly.
Allocated stack size was increased from 512 to 768 bytes.
Describe and descc were modified not to be dependant on the size
of integers.
Ran source files through indent(1).
v1.0 Feb 1994
Initial release for describe and descc.
AUTHORS
=======
The original describe and descc utilities and the describe format were
written by James Brookes <jamesb@ecst.csuchico.edu>.
The descu utility and v1.01 modifications to describe and descc were by
Devin Reade <gdr@myrias.ab.ca>.
v1.02/1.03 modifications to describe, descc and descu were by Soenke Behrens
<sbehrens@contech.demon.co.uk>.
LEGALESE
========
The describe and descc utilities are copyright (c) 1994-1995 by James
Brookes. The descu utility is copyright (c) 1995 by Devin Reade.
These programs may be freely copied provided that the archive, including
source files and this README, remain intact. Modified versions of these
programs may not be distributed without the permission of the respective
authors.
Contact the respective authors for permission to include these programs on
any commercial software collections. Permission is granted to Usenet sites
and GEnie Information Services for inclusion in software archives.
The Apple IIGS executable files distributed with this archive contain
material from the ORCA/C Run-Time Libraries, copyright 1987-1995 by
Byte Works, Inc. Used with permission.

View File

@ -1,30 +0,0 @@
#pragma optimize -1
#include <string.h>
#include <stdio.h>
#include <unistd.h>
char *basename (char *name) {
char *p, brk;
/* checking for ':' is GS-specific */
brk = (strchr(name,':')) ? ':' : '/';
p = strrchr(name,brk);
return ((p) ? p+1 : name);
}
#ifdef SHELLCOMD
int main (int argc, char **argv) {
if (argc != 2) {
fprintf(stderr,"Usage: basename file_name\nVersion 1.0\n");
return -1;
}
printf("%s\n",basename(argv[1]));
return 0;
}
#endif /* SHELLCOMD */

View File

@ -1,54 +0,0 @@
/*
* Header file for the describe package. This file is
* used by describe(1), descc(8), and descu(8).
*/
#define QUOTE_CHAR '#'
#define DATABASE "/usr/local/lib/describe"
#define FIELD_LEN 9
#define NAME_LEN 34
#define MAX_LINE_LENGTH 81
#define FIELD_COUNT 7 /* number of fields below, not including comments */
#define NAME "Name: "
#define VERSION "Version: "
#define SHELL "Shell: "
#define AUTHOR "Author: "
#define CONTACT "Contact: "
#define WHERE "Where: "
#define FTP "FTP: "
#define NAME_SHORT "Name:"
#define VERSION_SHORT "Version:"
#define SHELL_SHORT "Shell:"
#define AUTHOR_SHORT "Author:"
#define CONTACT_SHORT "Contact:"
#define WHERE_SHORT "Where:"
#define FTP_SHORT "FTP:"
#ifndef FALSE
# define FALSE 0
# define TRUE 1
#endif
typedef short int2;
typedef long int4;
typedef struct nameEntry_tag {
char name[NAME_LEN];
long int offset;
} nameEntry;
typedef struct descEntryTag {
char *name;
char *data;
} descEntry;
extern int optind;
extern char *optarg;
/* extern int getopt_restart(void); */
extern void begin_stack_check(void);
extern int end_stack_check(void);
extern char *basename(char *);

View File

@ -1,97 +0,0 @@
.TH DESCC 8 "System Administration" "7 May 1995" "Version 1.0.3"
.SH NAME
descc \- the describe(1) source compiler
.SH SYNOPSIS
.BR descc " [" -hV ]
.I sourcefile
.SH DESCRIPTION
.BR descc
compiles the describe source file
.I sourcefile
and saves the result to the system describe database.
.SH OPTIONS
.nf
\fB-h\fR Show usage information.
\fB-V\fR Show version information.
.fi
.SH "FILE FORMATS"
The describe source file consists of comments and records. A comment
is any line starting with the
.BR #
character. Each record consists of eight fields. The first
seven consist of one line of text and begin with the following identifiers:
.nf
Name: (The name of the program.)
Version: (The current version number.)
Shell: (The shell(s) the program was written for.)
Author: (The author or maintainer of the program.)
Contact: (How to contact the Author, typically an
email address.)
Where: (Where the program should be installed.)
FTP: (An ftp site from which the program may be
obtained.)
.fi
The last field consists of multiple lines of text. It should be
a brief description of the program. The following is an example of
a complete record:
.nf
Name: describe
Version: 1.0.3
Shell: ORCA/Shell, GNO/ME
Author: James Brookes
Contact: jamesb@ecst.csuchico.edu
Where: /usr/local/bin
FTP: ftp.cco.caltech.edu
Print a multi-line description obtained from the compiled
'describe' database; giving utility name, version, intended shell,
author, author's contact, where the utility is, as well as where the
utility can be FTPd from on the InterNet.
.fi
.LP
The describe database file consists of a
.BR Header ,
a set of
.BR "Name Entries" ,
and a set of
.BR Records ,
in the following format:
.nf
Header
2 bytes: Short Int, number of \fBName Entries\fR
Name Entries
34 bytes: NULL-terminated string; name of the utility.
4 bytes: Long Int, offset of the \fBrecord\fR in file.
Records
8 variable-length NULL-terminated strings.
.fi
.SH FILES
/usr/local/lib/describe \- the system
.B describe
database. If the environment variable
.B DESCDB
is set, its value will be used instead.
.SH ENVIRONMENT
.IP DESCDB
Full path to the system describe database. If
.B DESCDB
is set, its value is used instead of the default location
/usr/local/lib/describe.
.SH AUTHOR
James Brookes <jamesb@ecst.csuchico.edu>.
.SH "SEE ALSO"
.BR apropos (1),
.BR describe (1),
.BR man (1),
.BR whatis (1),
.BR descu (8).

View File

@ -1,282 +0,0 @@
/* */
/* descc - compile info file into describe database file */
/* */
/* v1.0.3 - No changes, but changed version number to keep */
/* in line with descu. */
/* Soenke Behrens [Sun Jan 28 1996] */
/* */
/* v1.0.2 - One bug removed. Recompiled to accomodate new */
/* SHELL line and DESCDB environment var */
/* Soenke Behrens [Sun Oct 22 1995] */
/* */
/* v1.0.1 - Added -h and -V flags [Sat May 06 1995] */
/* Extracted certain #defines to "desc.h" */
/* Now uses getopt for command line parsing. */
/* Fixed some potential bugs. */
/* */
/* v1.0.0 - James Brookes [Sat Oct 23 1993] */
/* released [Thu Mar 31 1994] [!!!!!!!!!!!] */
/* */
/* This version implements the following features: */
/* */
/* o Compiles a text file which follows the specifications in the */
/* included file 'describe.format'. The format of the describe */
/* database is as follows: */
/* */
/* Header */
/* */
/* 2 bytes: Short Int, number of Name Entries */
/* */
/* Name Entries */
/* */
/* 34 bytes: Null-terminated string; name of utility */
/* 4 bytes: Long Int, offset of record in file. */
/* */
/* Records */
/* */
/* 8 variable-length Null-terminated strings. */
/* */
#pragma optimize 15
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <getopt.h>
#include <assert.h>
#include "desc.h"
#define _VERSION_ "v1.0.3"
/* prototypes */
void usage(char *callname);
void version(char *callname);
void puke(int error,int lines);
int mygets(char *buffer, int2 *lines, FILE *FInPtr);
char *strdup (const char *str);
int Vflag;
/* version - print it out */
void version (char *callname) {
Vflag++;
fprintf(stderr,"%s version %s\n",callname,_VERSION_);
return;
}
/* */
/* usage - you know what to do */
/* */
void usage (char *callname) {
if (!Vflag) version(callname);
fprintf(stderr,"usage: %s [-hV] <describe_sourcefile>\n",callname);
exit(-1);
}
/* */
/* puke - stdlib errors */
/* */
void puke (int error,int lines) {
fprintf(stderr,"\nError $%x in line %d of script\n",error,lines);
fflush(stdout);
exit(error);
}
/* */
/* mygets - get a line (skipping commented lines) and increment line count */
/* */
int mygets (char *buffer, int2 *lines, FILE *FInPtr) {
char *p, c;
do {
if (fgets(buffer,MAX_LINE_LENGTH,FInPtr)==NULL) {
return(-1);
}
p = buffer + strlen(buffer) - 1; /* remove trailing \n */
if (*p == '\n') {
*p = '\0';
} else {
fprintf(stderr,"Line %d exceeds %d characters. Remainder ignored.\n",
*lines,MAX_LINE_LENGTH-1);
do {
c = fgetc(FInPtr);
} while ((c!='\n') && !feof(FInPtr));
}
(*lines)++;
} while(buffer[0] == QUOTE_CHAR || buffer[0] == '\n');
return(0);
}
/* */
/* Mainline */
/* */
int main (int argc, char **argv) {
FILE *FInPtr, *FOutPtr;
long int *record_locs, currLoc, endOfFile;
char *buffer;
int2 lines, namecount, i, j;
nameEntry nameStruct;
int c, errflag;
char *db_path;
/* initialize globals */
Vflag=0;
errflag=0;
#ifdef STACK_CHECK
begin_stack_check();
#endif
assert(sizeof(int2)==2);
assert(sizeof(int4)==4);
/* Get database path: If DESCDB is set, use it,
otherwise use DATABASE */
if (getenv("DESCDB") == 0)
{
if ((db_path = strdup(DATABASE)) == 0)
{
fprintf(stderr,"couldn't allocate path variable\n");
exit (-1);
}
} else {
if ((db_path = strdup(getenv("DESCDB"))) == 0)
{
fprintf(stderr,"couldn't allocate path variable\n");
exit (-1);
}
}
/* parse command line */
while ((c = getopt(argc, argv, "hV")) != EOF) {
switch (c) {
case 'V':
version(basename(argv[0]));
break;
case 'h': /*FALLTHROUGH*/
default:
errflag++;
break;
}
}
if (errflag || (argc-optind != 1))
{
free (db_path);
usage(basename(argv[0]));
}
/* open input and output files */
if ((buffer = malloc (MAX_LINE_LENGTH)) == NULL) {
fprintf(stderr,"couldn't allocate line buffer\n");
free (db_path);
exit (-1);
}
if ((FInPtr = fopen(argv[argc-1],"r")) == NULL) {
fprintf(stderr,"Error opening %s; exiting.\n",argv[argc-1]);
free (db_path);
free(buffer);
exit(1);
}
if ((FOutPtr = fopen(db_path,"wb+")) == NULL) {
fprintf(stderr,"Error opening database file %s; exiting.\n",db_path);
free (db_path);
free(buffer);
exit(1);
}
/* Compile array of names */
lines = 0;
namecount = 0;
/* space for # of array entries */
fwrite((void *)&namecount,sizeof(namecount),1,FOutPtr);
while(mygets(buffer,&lines,FInPtr) != -1) {
if (!strncmp(buffer,NAME,FIELD_LEN)) { /* found a match */
strncpy(nameStruct.name,&buffer[FIELD_LEN],NAME_LEN-1);
nameStruct.name[NAME_LEN-1] = '\0';
fwrite((void *)&nameStruct,sizeof(nameStruct),1,FOutPtr);
namecount++;
}
}
if ((record_locs = malloc (namecount*sizeof(long int)))==NULL) {
fprintf(stderr,"malloc of record_locs failed (%ld bytes); exiting\n",
(long) namecount*sizeof(long int));
exit(-1);
}
rewind(FInPtr);
buffer[0] = '\0';
lines = 0;
fputc('\t',FOutPtr);
/* Increment to first field */
while (strncmp(buffer,NAME,FIELD_LEN)) /* found a match! */
mygets(buffer,&lines,FInPtr);
{ /* BUGBUG 22/10/95 Soenke Behrens */
/* ORCA/C does not advance the file position indicator */
/* correctly after above fputc(). This tries to remedy */
/* the situation. Take out once library has been fixed */
fprintf(FOutPtr,"Junk");
fseek(FOutPtr,-4,SEEK_CUR);
}
/* Write out records and keep track of their file offsets */
for (i = 0; i < namecount; i++) {
record_locs[i] = ftell(FOutPtr);
/* print out <Version>, <Shell>, <Author>, <Contact>, <Where>, <FTP> */
for (j = 0; j < FIELD_COUNT-1; j++) {
buffer[FIELD_LEN] = '\0';
mygets(buffer,&lines,FInPtr);
fprintf(FOutPtr,"%s\n",&buffer[FIELD_LEN]);
}
/* handle <description> field */
for (;;) {
if (mygets(buffer,&lines,FInPtr) == -1) break;
if (!strncmp(buffer,NAME,FIELD_LEN)) break;
fprintf(FOutPtr,"%s ",buffer);
}
fputc('\n',FOutPtr);
}
endOfFile = ftell(FOutPtr);
fflush(FOutPtr); /*gdr 1*/
rewind(FOutPtr);
fwrite((void *)&namecount,sizeof(namecount),1,FOutPtr);
fflush(FOutPtr); /*gdr 1*/
/* time to go through the record_locs array and backpatch in */
/* all the record locations. A little slower than necessary */
/* perhaps, but it gets the job done. */
for (i = 0; i < namecount; i++) {
fread(&nameStruct,sizeof(nameStruct),1,FOutPtr);
fseek(FOutPtr,-(sizeof(nameStruct)),SEEK_CUR);
nameStruct.offset = record_locs[i];
fwrite((void *)&nameStruct,sizeof(nameStruct),(size_t) 1,FOutPtr);
fflush(FOutPtr);
}
fseek(FOutPtr,endOfFile,SEEK_SET);
fclose(FOutPtr);
free(db_path);
free(record_locs);
free(buffer);
#ifdef STACK_CHECK
fprintf(stderr,"stack usage: %d bytes\n",end_stack_check());
#endif
return 0;
}

View File

@ -1,10 +0,0 @@
Name: descc
Version: 1.0.3
Shell: ORCA/Shell, GNO/ME
Author: James Brookes
Contact: jamesb@ecst.csuchico.edu
Where: /usr/sbin
FTP: ftp.cco.caltech.edu
Compile a source file into a 'describe' database file.

View File

@ -1,56 +0,0 @@
.TH DESCRIBE 1 "Commands and Applications" "7 May 1995" "Version 1.0.3"
.SH NAME
describe \- show information about a program
.SH SYNOPSIS
.BR describe " [" -hvV ]
.I program
.SH DESCRIPTION
.BR describe
will show current information about
.IR program .
This information includes:
.nf
The name of the program;
The program version number;
The shell the program was written for;
The author (or the person currently maintaining the program);
Contact information for the author;
Where the utility should be installed;
An FTP site from which the program may be obtained, and;
A brief description of the program.
.fi
.LP
.BR describe
uses a database compiled by
.BR descc (8).
.SH OPTIONS
.nf
\fB-h\fR Show usage information.
\fB-v\fR Verbose debugging mode.
\fB-V\fR Show version information.
.fi
.SH FILES
/usr/local/lib/describe \- the system
.B describe
database. If the environment variable
.B DESCDB
is set, its value will be used instead.
.SH ENVIRONMENT
.IP DESCDB
Full path to the system describe database. If
.B DESCDB
is set, its value is used instead of the default location
/usr/local/lib/describe.
.SH AUTHOR
James Brookes <jamesb@ecst.csuchico.edu>.
.SH "SEE ALSO"
.BR apropos (1),
.BR man (1),
.BR whatis (1),
.BR descc (8),
.BR descu (8).

View File

@ -1,238 +0,0 @@
/*
* describe(1) -- Copyright 1993-1995 James Brookes. See the README and
* man page for details.
*
* We have to have this pragma in here; Orca/C's bit 5 optimization
* (loop invariant removal) kills code somewhere in this file, resulting
* in a system panic.
*/
#pragma optimize 31
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <ctype.h>
#include <getopt.h>
#include "desc.h"
#define _VERSION_ "v1.0.3"
/* prototypes */
void usage(char *callname);
void print_entry(FILE *FInPtr, long int index);
void myprintf(char *string, int wordwrap_size);
char *strdup (const char *str);
int Vflag;
void version (char *callname) {
Vflag++;
fprintf(stderr,"%s version %s\n",callname,_VERSION_);
return;
}
void usage(char *callname) {
if (!Vflag) version(callname);
fprintf(stderr,"usage: %s [-hv] <utility_name>\n",callname);
exit(-1);
}
void myprintf(char *string, int wordwrap_size) {
int length = 0;
char *headString, *tailString;
headString = tailString = string;
printf("\n");
while (1) {
tailString++; length++;
if (*tailString == '\0') {
printf("%s",headString);
return;
} else if (length == wordwrap_size) {
while (*tailString != ' ')
tailString--;
*tailString = '\0';
printf("%s\n",headString);
headString = tailString+1;
length = 0;
}
}
}
void print_entry(FILE *FInPtr, long int index) {
char *buffer;
int i;
if ((buffer = (char *) malloc (1024)) == 0)
{
fprintf(stderr,"couldn't allocate buffer\n");
exit (-1);
}
fseek(FInPtr,index,SEEK_SET);
printf("%s",VERSION);
fgets(buffer,MAX_LINE_LENGTH,FInPtr);
printf("%s",buffer);
printf("%s",SHELL);
fgets(buffer,MAX_LINE_LENGTH,FInPtr);
printf("%s",buffer);
printf("%s",AUTHOR);
fgets(buffer,MAX_LINE_LENGTH,FInPtr);
printf("%s",buffer);
printf("%s",CONTACT);
fgets(buffer,MAX_LINE_LENGTH,FInPtr);
printf("%s",buffer);
printf("%s",WHERE);
fgets(buffer,MAX_LINE_LENGTH,FInPtr);
printf("%s",buffer);
printf("%s",FTP);
fgets(buffer,MAX_LINE_LENGTH,FInPtr);
printf("%s",buffer);
fgets(buffer,1024,FInPtr);
myprintf(buffer,75);
free(buffer);
#ifdef STACK_CHECK
printf("Stack: %d\n",end_stack_check());
#endif
exit(0);
}
int main (int argc, char **argv) {
FILE *FInPtr;
char searchName[NAME_LEN];
int2 verbose, numOfEntries, cmp, offset1, offset2, check, i;
nameEntry nameStruct;
int c, errflag;
char *p, *tmp;
char *db_path;
#ifdef STACK_CHECK
begin_stack_check();
#endif
verbose = FALSE;
Vflag = FALSE;
errflag = FALSE;
/* Get database path: If DESCDB is set, use it,
otherwise use DATABASE */
if (getenv("DESCDB") == 0)
{
if ((db_path = strdup(DATABASE)) == 0)
{
fprintf(stderr,"couldn't allocate path variable\n");
exit (-1);
}
} else {
if ((db_path = strdup(getenv("DESCDB"))) == 0)
{
fprintf(stderr,"couldn't allocate path variable\n");
exit (-1);
}
}
while ((c = getopt(argc,argv,"hvV")) != EOF) {
switch (c) {
case 'v':
verbose = TRUE;
break;
case 'V':
version(basename(argv[0]));
break;
case 'h':
default:
errflag = TRUE;
break;
}
}
if (errflag || (argc-optind != 1))
{
free (db_path);
usage(basename(argv[0]));
}
if ((FInPtr = fopen(db_path,"rb")) == NULL) {
perror("couldn't open database");
free (db_path);
exit(-1);
}
fread(&numOfEntries,2,1,FInPtr);
offset1 = 0;
offset2 = numOfEntries-1;
strcpy(searchName,argv[optind]);
i=0;
p = searchName;
while (*p) {
*p = tolower(*p);
p++;
}
if (verbose)
printf("Searching...\n");
while (1) {
check = ((offset2-offset1)/2) + offset1;
fseek(FInPtr,2+(check*sizeof(nameEntry)),SEEK_SET);
fread(&nameStruct,sizeof(nameEntry),1,FInPtr);
if((tmp = strdup(nameStruct.name)) == 0)
{
fprintf(stderr,"couldn't copy name string\n");
free (db_path);
exit (-1);
}
p = nameStruct.name;
while (*p) {
*p = tolower(*p);
p++;
}
cmp = strcmp(nameStruct.name,searchName);
if (verbose)
printf(" checked %s\n",tmp);
if (cmp > 0) { /* name bigger than searchName */
offset2 = check-1;
} else if (cmp < 0) { /* name smaller than searchName */
offset1 = check+1;
} else {
if (verbose) {
printf("Found entry %s!\n",tmp);
#ifdef STACK_CHECK
printf("Stack: %d\n",end_stack_check());
#endif
free (db_path);
free (tmp);
exit(0);
}
printf("%s%s\n",NAME,tmp);
free (db_path);
free (tmp);
print_entry(FInPtr,nameStruct.offset);
}
if (offset1 > offset2) {
printf("Entry '%s' not found in describe database.\n",searchName);
#ifdef STACK_CHECK
printf("Stack: %d\n",end_stack_check());
#endif
free (db_path);
free (tmp);
exit(1);
}
}
}

View File

@ -1,12 +0,0 @@
Name: describe
Version: 1.0.3
Shell: ORCA/Shell, GNO/ME
Author: James Brookes
Contact: jamesb@ecst.csuchico.edu
Where: /usr/local/bin
FTP: ftp.cco.caltech.edu
Print a multi-line description obtained from the compiled 'describe'
database; giving utility name, version, intended shell, author, author's
contact, where the utility is, as well as where the utility can be FTPd
from on the InterNet.

File diff suppressed because it is too large Load Diff

View File

@ -1,58 +0,0 @@
.TH DESCU 8 "System Administration" "7 May 1995" "Version 1.0.3"
.SH NAME
descu \- the describe(1) source updater
.SH SYNOPSIS
.BR descu " [" -hV ]
.I sourcefile
.I patchfile1
[
.IR patchfile2 " ..."
]
.SH DESCRIPTION
.BR descu
updates the describe source file
.I sourcefile
by applying the new and updated records from the \fIpatchfile\fRs
and prints the result to standard output.
.LP
.IR Patchfile s
are just one or more describe source entries as defined in
.BR descc (8).
(They have nothing to do with
.BR patch (1).)
.LP
.IR Patchfile s
are assumed to contain at most one entry (in all listed
.IR patchfile s)
for a given program, keyed on the
.BR Name:
field. If an entry in
.IR patchfile
is already in
.IR sourcefile ,
it replaces the original; otherwise the entry is appended. In both
cases, the output is sorted lexicographically (ignoring case), based on
the
.BR Name:
field.
.LP
.BR descu
will create the file
.B descu.rej
in the current directory. This contains all records that were removed
from
.IR sourcefile .
.SH OPTIONS
.nf
\fB-h\fR Show usage information.
\fB-V\fR Show version information.
.fi
.SH AUTHOR
Devin Reade <gdr@myrias.ab.ca>
.SH "SEE ALSO"
.BR apropos (1),
.BR describe (1),
.BR man (1),
.BR whatis (1),
.BR descc (8).

View File

@ -1,520 +0,0 @@
/*
* descu - describe(1) update utility for maintaining describe source files
*
* Usage: descu [-hV] sourcefile patchfile1 [patchfile2 ...]
*
* Options:
* -h show usage information and exit.
* -V show version information
*
* Copyright 1995 by Devin Reade for James Brookes' describe(1) utility.
* See the included README file and man page for details.
*
* $Id: descu.c,v 1.3 1996/01/28 17:39:29 gdr Exp $
*/
#pragma optimize -1
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <unistd.h>
#include <stdio.h>
#include <errno.h>
#include <stdlib.h>
#include <string.h>
#include <assert.h>
#include <ctype.h>
#include <getopt.h>
#include "desc.h"
#define _VERSION_ "v1.0.3"
#define MAX_BUFFER 65534
#define SLOTS_QUANTUM 20
#define REJECT_FILE "descu.rej"
#ifndef __ORCAC__
ssize_t read(int, void *, size_t);
#endif
char *strerror(int);
void convert (char *);
int my_stricmp (const char *cs, const char *ct);
char *versionStr = _VERSION_;
static char *header=NULL; /* comments before the first describe entry */
static char *trailer=NULL; /* comments after the last describe entry */
short oflag;
short Vflag;
short errflag;
descEntry **entryArray1=NULL;
descEntry **entryArray2=NULL;
int array1SlotsAlloced=0;
int array2SlotsAlloced=0;
int array1SlotsUsed=0;
int array2SlotsUsed=0;
/*
* inhale - read file into buffer
*
* Pre: <pathname> is the path name of the file to read in
*
* Post: returns a malloc'd NULL-terminated buffer containing the contents
* of file <pathname>. On error, returns NULL and prints a suitable
* message.
*
* On the Apple IIgs, CR's are also converted to LF's
*/
char *inhale (char *pathname) {
char *buffer;
long bytecount, bytes_read;
ssize_t i;
int fd;
/* open the file */
if ((fd = open(pathname,O_RDONLY))==-1) {
fprintf(stderr,"inhale: open of %s failed: %s\n",
pathname,strerror(errno));
return NULL;
}
/* create the buffer */
bytecount = lseek(fd,(off_t) 0,SEEK_END);
if (bytecount > MAX_BUFFER) {
fprintf(stderr,"descu internal error: cannot handle files greater"
"than %d bytes\n due to a compiler bug. Sorry.\n",
MAX_BUFFER);
exit(-1);
}
lseek(fd,(off_t) 0, SEEK_SET);
if ((buffer = malloc(bytecount+1))==NULL) {
fprintf(stderr,"inhale: malloc of %ld-byte buffer failed for file %s:%s\n",
bytecount+1,pathname,strerror(errno));
close(fd);
return NULL;
}
/* read file into the buffer */
bytes_read=0;
while (bytes_read < bytecount) {
i = read(fd,&buffer[bytes_read],(size_t)bytecount-bytes_read);
if (i==-1) {
fprintf(stderr,"inhale: read failed on file %s:%s\n",
pathname,strerror(errno));
free(buffer);
close(fd);
return NULL;
}
bytes_read += i;
}
/* clean up and return buffer */
close(fd);
buffer[bytecount] = '\0';
#ifdef __ORCAC__
/* convert CR to LF */
{
char *p;
for (p=buffer; *p ; p++) {
if (*p == 0x0D) *p = 0x0A;
}
}
#endif
return buffer;
}
/*
* extract_info -- take a string buffer containing the describe information
* and return a malloc'd descEntry structure containing
* pointers into the buffer of the various parts. Also
* modifies the buffer so that there is a '\0' character
* between the parts.
*/
descEntry *extract_info(char *source) {
char *p;
descEntry *entry;
if ((entry = malloc(sizeof(descEntry))) == NULL) {
perror("add_entry: couldn't allocate new entry");
exit(1);
}
/* extract out name */
if (((entry->name = strstr(source,NAME_SHORT))==NULL) ||
((p = strchr(source,'\n'))==NULL)) {
fprintf(stderr,"bad or missing describe field: \"%s\"\n"
"describe entry is:\n%s\n",NAME,source);
free(entry);
return NULL;
}
/* extract out data */
entry->data = p+1;
/* terminate the name, dropping trailing space */
do { --p; } while (isspace(*p));
*(p+1) = '\0';
return entry;
}
/*
* add_entry -- add entry to the descTable, even if it already exists.
*/
void add_entry(descEntry *entry, int initial_buffer) {
descEntry **e, ***array;
int *slotsAlloced, *slotsUsed;
if (initial_buffer) {
array = &entryArray1;
slotsAlloced = &array1SlotsAlloced;
slotsUsed = &array1SlotsUsed;
} else {
array = &entryArray2;
slotsAlloced = &array2SlotsAlloced;
slotsUsed = &array2SlotsUsed;
}
/* grow array if necessary */
if (*slotsAlloced == *slotsUsed) {
*slotsAlloced += SLOTS_QUANTUM;
if (*array) {
e = realloc(*array,(*slotsAlloced) * sizeof(descEntry *));
} else {
e = malloc((*slotsAlloced) * sizeof(descEntry *));
}
if (e == NULL) {
perror("couldn't grow describe array");
exit(1);
}
*array = e;
}
/* add in the entry */
(*array)[*slotsUsed] = entry;
(*slotsUsed)++;
return;
}
/*
* insert - insert all entries contained in buffer into the descTable.
* If initial_buffer is non-zero, then use any comments preceeding
* the first entry as the output file header, and any comments
* following the last entry as the output file trailer. If
* initial_buffer is zero, then the respective comment blocks are
* ignored, effectively deleting them from the output.
*/
void insert(char *buffer, int initial_buffer) {
char *p, *q;
descEntry *entry;
/* pull out the header (if nec) and init p */
if (initial_buffer) header = buffer;
p = strstr(buffer,NAME_SHORT);
if(!p) return; /* buffer doesn't have any describe entries! */
*(p-1)='\0';
/* add all but the last entry */
while ((q=strstr(p+1,NAME_SHORT))!=NULL) {
*(q-1)='\0';
entry = extract_info(p);
if (entry) add_entry(entry, initial_buffer);
p=q;
}
/* extract out the trailer and add the last entry */
if ((q = strstr(p,"\n#"))==NULL) {
if (initial_buffer) trailer="";
} else {
if (initial_buffer) trailer=q+1;
*q = '\0';
}
entry = extract_info(p);
if (entry) add_entry(entry,initial_buffer);
return;
}
/*
* sortArray - do a heapsort on <array> consisting of <slotsUsed> elements.
* The sort is based on the field array[i]->name, sorted
* lexicographically ignoring case.
*/
void sortArray(descEntry **array, int slotsUsed) {
int l, j, ir, i;
descEntry *rra;
if (slotsUsed==1) return; /* no need to sort one element */
--array; /* fudge since the algorithm was designed */
/* for a unit-indexing */
l = (slotsUsed>>1) + 1;
ir = slotsUsed;
/*
* The index l will be decremented from its initial value down to 0 during
* the heap creation phase. Once it reaches 0, the index ir will be
* decremented from its initial value down to 0 during the heap selection
* phase.
*/
for (;;) {
if (l > 1) /* still in creation phase */
rra = array[--l];
else { /* in selection phase */
rra= array[ir]; /* clear a space at the end of array */
array[ir] = array[1]; /* retire the top of the heap into it */
if (--ir == 1) { /* done with the last promotion */
array[1] = rra;
return;
}
}
i = l; /* set up to sift down element rra to its proper place */
j = l << 1;
while (j<=ir) {
if (j<ir && (my_stricmp(array[j]->name,array[j+1]->name)<0)) ++j;
if (my_stricmp(rra->name,array[j]->name)<0) { /* demote rra */
array[i] = array[j];
i = j;
j += i;
} else j = ir + 1; /* this is rra's level; set j to terminate */
} /* the sift-down */
array[i] = rra;
}
}
/*
* int my_stricmp (const char *cs, const char *ct);
*
* Compare the two strings cs and ct case-insensitive. Return
* <0 if cs<ct, 0 if cs == ct, >0 if cs>ct.
*
*/
int my_stricmp (const char *cs, const char *ct)
{
char a, b;
while ((a = tolower(*cs)) && (b = tolower(*ct))) {
if (a < b) return -1;
if (a > b) return 1;
cs++; ct++;
}
if (*cs == *ct) return 0; /* cs and ct of same length */
else if (*cs) return 1; /* cs longer than ct */
else return -1; /* cs shorter than ct */
}
/*
* ns_stricmp (no-space string compare) -- compare two strings
* case-insensitive, ignoring a leading NAME_SHORT and whitespace,
* and ignoring trailing whitespace.
*
* Returns zero if strings are equal, -1 if a<b, 1 if a>b.
* The following are therefore equal:
* "Name: test "
* "Name: test "
* The following are inequal:
* "Name: one"
* "Name: two"
*/
int ns_stricmp (char *a, char *b) {
char *p;
char ca, cb;
size_t len;
/* strip NAME_SHORT and leading space */
len = strlen(NAME_SHORT);
a+=len;
b+=len;
while (isspace(*a)) a++;
while (isspace(*b)) b++;
/* strip trailing space */
p = a + strlen(a);
do {
--p;
} while (isspace(*p));
*(p+1) = '\0';
p = b + strlen(b);
do {
--p;
} while (isspace(*p));
*(p+1) = '\0';
/* do the string comparison */
while ((ca = tolower(*a)) && (cb = tolower(*b))) {
if (ca < cb) return -1;
if (ca > cb) return 1;
a++; b++;
}
if (*a == *b) return 0; /* a and b of same length */
else if (*a) return 1; /* a longer than b */
else return -1; /* a shorter than b */
}
void version (char *progName) {
fprintf(stderr,
"%s version %s Copyright 1995 Devin Reade\n"
"Freeware. See the manual page for copying restrictions.\n",
progName,versionStr);
return;
}
/*
* Usage -- print usage info and exit
*/
void usage(char *progName) {
if (!Vflag || errflag) {
fprintf(stderr,
"%s -- describe(1) source update utility\n"
"Usage: %s [-hV] sourcefile patchfile1 [patchfile2 ...]\n"
"\t-h\tshow usage information\n"
"\t-V\tshow version information\n\n",
progName,progName);
}
version(progName);
exit(1);
}
/*
* need I say it?
*/
int main(int argc, char **argv) {
char *buffer;
int i, j;
FILE *outfp, *rejfp;
int c;
char *outputfile=NULL;
int compare;
#ifdef STACK_CHECK
begin_stack_check();
#endif
/* initialize */
errflag=0;
oflag=0;
/* parse command line */
while ((c=getopt(argc,argv,"ho:V"))!=EOF) {
switch (c) {
case 'o':
outputfile = optarg;
oflag++;
break;
case 'V':
Vflag++;
break;
case 'h':
default:
errflag++;
}
}
/* error and exit if necessary */
if (errflag || (argc-optind<2)) usage(basename(argv[0]));
/* show version info */
if (Vflag) version(basename(argv[0]));
/* open output (if nec) and reject file */
if (oflag) {
if ((outfp = fopen(outputfile,"w+"))==NULL) {
perror("main: couldn't open output file");
exit(1);
}
} else {
outfp = stdout;
}
if ((rejfp = fopen(REJECT_FILE,"w+"))==NULL) {
perror("main: couldn't open rejects file");
exit(1);
}
/* read in original describe source file */
buffer = inhale(argv[optind]);
insert(buffer,1);
/* insert describe patch files */
for (optind++; optind<argc; optind++) {
buffer = inhale(argv[optind]);
insert(buffer,0);
}
/* sort the two arrays */
sortArray(entryArray1,array1SlotsUsed);
sortArray(entryArray2,array2SlotsUsed);
/*
* merge the two arrays, printing out the result
*/
i=0; j=0;
/* print the header */
fprintf(outfp,"%s\n",header);
/* first stage; merge while we have two arrays */
while ((i<array1SlotsUsed) && (j<array2SlotsUsed)) {
compare = ns_stricmp (entryArray1[i]->name, entryArray2[j]->name);
if (compare < 0) {
fprintf(outfp,"%s\n%s\n",entryArray1[i]->name,entryArray1[i]->data);
i++;
} else if (compare > 0) {
fprintf(outfp,"%s\n%s\n",entryArray2[j]->name,entryArray2[j]->data);
j++;
} else {
fprintf(rejfp,"%s\n%s\n",entryArray1[i]->name,entryArray1[i]->data);
fprintf(outfp,"%s\n%s\n",entryArray2[j]->name,entryArray2[j]->data);
i++; j++;
}
}
/* second stage; print out remaining list */
while (i<array1SlotsUsed) {
fprintf(outfp,"%s\n%s\n",entryArray1[i]->name,entryArray1[i]->data);
i++;
}
while (j<array2SlotsUsed) {
fprintf(outfp,"%s\n%s\n",entryArray2[j]->name,entryArray2[j]->data);
j++;
}
/* print the trailer */
fprintf(outfp,"%s",trailer);
/* close the files and exit */
fclose(rejfp);
if (oflag) fclose(outfp);
#ifdef STACK_CHECK
fprintf(stderr,"stack usage: %d bytes\n",end_stack_check());
#endif
return 0;
}

View File

@ -1,10 +0,0 @@
Name: descu
Version: 1.0.3
Shell: ORCA/Shell, GNO/ME
Author: Devin Reade
Contact: gdr@myrias.ab.ca
Where: /usr/sbin
FTP: ftp.cco.caltech.edu
Update a 'describe' source file.

View File

@ -1,44 +0,0 @@
#
# This is the makefile for the describe(1) package. It is for use
# with dmake(1).
#
# Use -DSTACK_CHECK in CFLAGS to show stack usage.
CFLAGS += -O -v -I/usr/include -s768
LDFLAGS += -v
LDLIBS +=
BINDIR = /usr/local/bin
SBINDIR = /usr/sbin
MANDIR = /usr/man
INSTALL = /bin/cp
build: describe descc descu
descc: descc.o basename.o descc.r
@purge
$(CC) $(LDFLAGS) descc.o basename.o -o $@ $(LDLIBS)
copyfork descc.r descc
describe: describe.o basename.o describe.r
@purge
$(CC) $(LDFLAGS) describe.o basename.o -o $@ $(LDLIBS)
copyfork describe.r describe
descu: descu.o basename.o vaend.o descu.r
@purge
$(CC) $(LDFLAGS) descu.o basename.o vaend.o -o $@ $(LDLIBS)
copyfork descu.r descu
descc.o:: desc.h
describe.o:: desc.h
descu.o:: desc.h
install:
$(RM) -f /usr/local/bin/descc
$(INSTALL) describe $(BINDIR)
$(INSTALL) descc $(SBINDIR)
$(INSTALL) descu $(SBINDIR)
$(INSTALL) describe.1 $(MANDIR)/man1
$(INSTALL) descc.8 $(MANDIR)/man8
$(INSTALL) descu.8 $(MANDIR)/man8

View File

@ -1,13 +0,0 @@
/*
* Work around a change in the ORCA/C libraries: function va_end
* is now __va_end, which breaks some GNO/ME libraries.
*/
#include <stdarg.h>
#undef va_end
void va_end (va_list ap)
{
__va_end (ap);
}

View File

@ -1,81 +0,0 @@
=============================================================================
udl - Convert EOL formats freely between MS-DOS (CR/LF), Unix/Amiga (LF),
and Apple (CR).
(c) 1993-1996 Soenke Behrens, Devin Reade
Version 1.1.5
$Id: HISTORY,v 1.2 1996/02/11 20:05:45 gdr Exp $
=============================================================================
Udl converts text files between CR, LF and CR/LF (Apple, Unix and MS-DOS).
It is a very fast utility that ensures that the integrity of the file
cannot be compromised during the translation. It is also much easier
to use than tr(1).
================
Revision History:
================
v1.0.1
Tabs are left alone now. Also recognizes CR/LF (MeSsy-DOS).
v1.0.2
Does no longer read in the complete file, instead creates a temp
file in prefix 3/.
v1.0.3
Fixed a bug, allocated not enough mem for strncpy.
v1.1
Changed to use static GS/OS strings again. Made faster by factor
5.8.
v1.1.1
Cleaned the code up a bit, wrote a Makefile, all output by udl is
prefixed with the name it was invoked with.
v1.1.2
Sped up Apple <-> Unix conversion further (factor 1.5).
v1.1.2 (Unix)
(December 1993)
Modified source to produce a Unix version
v1.1.3
(Updated by Devin Reade, November 1994)
Added ability to recurse through directories (-R flag).
Changed behavior to ignore binary files rather than exiting.
Merged Unix and Apple IIgs versions.
No message is printed out when a binary file (or, in the IIgs
implementation, a non-TXT or non-SRC file) is encountered
unless the -v option is specified.
v1.1.4
(Soenke Behrens, Devin Reade, February 1995)
udl creates a temporary file in the directory of the
source file, not in /tmp. This reduces the likelihood of
data loss in the event of a system crash or powerdown.
udl now accepts something like "udl -R directory/" without
affixing an extra '/' to "directory/".
Fixed bug (via the BROKEN_DIRENT_STRUCT macro) that was causing
filename-munging on Solaris. It seems that the sys/stat.h header
file doesn't agree with the stat implementation.
Modified Makefile.gs to properly write the new executable over
the old resource fork for udl. The resource fork originates with
the file udl.r.
Added suggested defines to the README for various Unix platforms.
Man page changes, including grammar and the deletion of a bug that
no longer exists.
Fixed bug where invoking 'udl -u directory' would attempt to
deref a NULL pointer, causing either memory tromping (IIgs) or
a core dump (Unix).
Tested under SunOS 4.x, SunOS 5.x (Solaris), and AIX.
v1.1.5
(Soenke Behrens, Devin Reade, January 1996)
Changed source slightly to compile under djgpp (MS-DOS) and Linux,
linted source
Unix makefile changed by Devin Reade to automatically detect OS type

View File

@ -1,15 +0,0 @@
History
Makefile.gs
Makefile.unx
Makefile.msd
Manifest
README
common.c
common.h
globals.c
udl.1
desribe.udl
udlgs.c
udl.rez
udlunix.c
udluse.c

View File

@ -1,60 +0,0 @@
#
# Makefile for udl
# Copyright (c) 1993-1996 Soenke Behrens, Devin Reade
#
# This makefile should be used with dmake.
#
# $Id: Makefile.gs,v 1.10 1996/02/11 20:05:47 gdr Exp $
#
# Where do we put the binaries and man page?
BINDIR = /usr/local/bin
MANDIR = /usr/local/man
# OS-dependant macros. See the README for an explanation of these.
DEFINES = -DGNO -D_POSIX_C_SOURCE -D_POSIX_SOURCE -DHAS_ATEXIT \
-DOVERFLOW_CHECK
# Use optimization and a 2k stack.
CFLAGS = $(DEFINES) -O -s2048
LDFLAGS = -s2048
# Depending on how you have your libraries set up, you may not need
# this next line. In that case, just comment it out.
# LDLIBS = -l/usr/lib/gnulib
#
# You should not have to modify anything beyond this point
#
OBJS = udl.o udluse.o common.o globals.o
udl: $(OBJS) udl.r help/udl
$(CC) $(LDFLAGS) $(OBJS) $(LDLIBS) -o $@
copyfork udl.r $@ -r
udl.o: udlgs.c common.h
$(CC) -c $(CFLAGS) -o udl.o udlgs.c
install:
cp -f udl $(BINDIR)
cp -f udl.1 $(MANDIR)/man1
help:
mkdir $@
help/udl: udl.1 help
nroff -man udl.1 > $@
clean:
-$(RM) *.o *.root udl.r
clobber: clean
-$(RM) -rf udl help
common.o:: common.h
globals.o:: common.h

View File

@ -1,44 +0,0 @@
#
# Makefile for udl
# (c) 1993-1996 Soenke Behrens
#
# $Id: Makefile.msd,v 1.2 1996/02/11 20:05:47 gdr Exp $
# DJGPP is a gcc port
CC = gcc
# Where do we put the binaries and man page?
BINDIR = /djgpp/bin
MANDIR = /djgpp/man
# OS-dependant macros. See the README for an explanation of these.
DEFINES = -DREADDIR_RETURNS_DOT -DHAS_ATEXIT
INSTALL = cp -f
CFLAGS = $(DEFINES) -O2
#
# You should not have to modify anything beyond this point
#
OBJS = udl.o udluse.o common.o globals.o
udl: $(OBJS)
$(CC) $(LDFLAGS) -o udl $(OBJS) $(LDLIBS)
udl.o: udlunix.c common.h
$(CC) -c $(CFLAGS) -o udl.o udlunix.c
install:
$(INSTALL) udl $(DESTDIR)$(BINDIR)
$(INSTALL) udl.1 $(DESTDIR)$(MANDIR)
clean:
-rm *.o *~ core
clobber: clean
-rm udl
udluse.o common.o globals.o:: common.h

View File

@ -1,94 +0,0 @@
#
# Makefile for udl
# (c) 1993-1996 Soenke Behrens, Devin Reade
#
# $Id: Makefile.unx,v 1.9 1996/02/11 20:05:48 gdr Exp $
#
# $(CC) _must_ be an ANSI compiler. Use gcc if your cc is not.
CC = cc
BINDIR = /usr/local/bin
MANDIR = /usr/local/man/man1
INSTALL = /usr/bin/install
# These are arguments to $(INSTALL)
MODE644 = -m 644
MODE755 = -m 755
OWNER_GROUP = -o bin -g sys
# You should not have to modify anything beyond this point
##########################################################
#
# OS-dependant macros. See the README for an explanation of these.
#
DEFINES_AIX = -DBROKEN_REALLOC -D_POSIX_C_SOURCE -D_POSIX_SOURCE
DEFINES_Linux = -DREADDIR_RETURNS_DOT -D_POSIX_C_SOURCE -D_POSIX_SOURCE \
-DHAS_ATEXIT
DEFINES_Solaris = -DREADDIR_RETURNS_DOT -D_POSIX_C_SOURCE -D_POSIX_SOURCE \
-DBROKEN_DIRENT_STRUCT
LDLIBS_Solaris = -lucb
DEFINES_SunOS = -DREADDIR_RETURNS_DOT -D_POSIX_C_SOURCE -D_POSIX_SOURCE \
-DBROKEN_REALLOC
CFLAGS = $(DEFINES_$(OS)) -O
LDFLAGS = $(LDFLAGS_$(OS)) -s
LDLIBS = $(LDLIBS_$(OS))
OBJS = udl.o udluse.o common.o globals.o
build:
@os_string=`uname -sr | tr ' ' '_'`; \
case $$os_string in \
SunOS_4*) os=SunOS;; \
SunOS_5*) os=Solaris;; \
AIX*) os=AIX;; \
Linux*) os=Linux;; \
*) echo "don't know about OS $$os_string"; \
exit -1;; \
esac; \
$(MAKE) udl -f Makefile.unx OS=$$os
udl: $(OBJS)
$(CC) $(LDFLAGS) -o udl $(OBJS) $(LDLIBS)
udl.o: udlunix.c common.h
$(CC) -c $(CFLAGS) -o udl.o udlunix.c
newudl.1: udl.1
@echo "creating newudl.1"; \
echo '/^.TH/ c\' > sed.script; \
echo '.TH UDL 1 "15 January 1996" "Version 1.1.5"\
"Commands and Applications"' >>sed.script; \
sed -f sed.script <udl.1 >newudl.1; \
rm -f sed.script
install: newudl.1 build
$(INSTALL) $(MODE755) $(OWNER_GROUP) udl $(BINDIR)
$(INSTALL) $(MODE644) $(OWNER_GROUP) newudl.1 $(MANDIR)/udl.1
rm -f newudl.1
clean:
-rm -f *.o *~ core
clobber: clean
-rm -rf udl newudl.1 help
dist: clobber
@echo "creating archive"; \
cwd=`pwd`; \
parent=`dirname $$cwd`; \
dir=`basename $$cwd`; \
cd $$parent; \
archive=$$dir.tar.Z; \
if [ -f $$archive ]; then \
echo "please move $$parent/$$archive out of the way, first"; \
exit -1; \
fi; \
tar -cf - $$dir | compress > $$archive
udluse.o common.o globals.o:: common.h

Some files were not shown because too many files have changed in this diff Show More