mirror of
https://github.com/GnoConsortium/gno.git
synced 2024-06-11 09:29:27 +00:00
This commit was manufactured by cvs2svn to create tag 'beta_970304'.
This commit is contained in:
parent
e5b9329e55
commit
a31db3db4a
|
@ -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
|
|
@ -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).
|
|
@ -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).
|
|
@ -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.
|
|
@ -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 */
|
|
@ -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.
|
|
@ -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
|
|
@ -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.
|
|
@ -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.
|
175
bin/tee/tee.c
175
bin/tee/tee.c
|
@ -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);
|
||||
}
|
|
@ -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"
|
||||
};
|
|
@ -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;
|
||||
}
|
|
@ -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>
|
|
@ -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 ""
|
||||
|
|
@ -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
|
||||
|
|
@ -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
|
|
@ -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
|
|
@ -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,
|
||||
};
|
|
@ -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 *, ...));
|
||||
|
275
bin/test/test.1
275
bin/test/test.1
|
@ -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.
|
582
bin/test/test.c
582
bin/test/test.c
|
@ -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");
|
||||
}
|
|
@ -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.
|
|
@ -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"
|
||||
};
|
|
@ -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 */
|
||||
}
|
|
@ -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
|
||||
|
|
@ -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
|
|
@ -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.
|
|
@ -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.
|
|
@ -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;
|
||||
}
|
|
@ -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.
|
||||
|
|
@ -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"
|
||||
};
|
|
@ -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.
|
|
@ -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
|
|
@ -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>
|
|
@ -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;
|
||||
}
|
|
@ -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.
|
|
@ -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"
|
||||
};
|
|
@ -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
|
|
@ -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.
|
|
@ -1 +0,0 @@
|
|||
.so man1/whatis.1
|
|
@ -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;
|
||||
}
|
|
@ -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;
|
||||
}
|
|
@ -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.
|
|
@ -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);
|
||||
}
|
|
@ -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;
|
||||
}
|
|
@ -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.
|
||||
|
|
@ -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;
|
||||
}
|
|
@ -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! */
|
||||
};
|
|
@ -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
|
|
@ -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)
|
|
@ -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;
|
||||
}
|
|
@ -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;
|
|
@ -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.
|
|
@ -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;
|
||||
}
|
|
@ -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);
|
|
@ -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;
|
||||
}
|
|
@ -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
|
|
@ -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;
|
||||
}
|
||||
|
|
@ -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);
|
|
@ -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 */
|
|
@ -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.
|
|
@ -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;
|
||||
}
|
|
@ -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
|
||||
|
|
@ -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
|
|
@ -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;
|
||||
}
|
||||
|
|
@ -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).
|
|
@ -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;
|
||||
}
|
|
@ -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;
|
||||
}
|
|
@ -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;
|
||||
}
|
|
@ -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;
|
||||
}
|
||||
|
|
@ -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
|
|
@ -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;
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
|
@ -1 +0,0 @@
|
|||
.so /usr/man/man1/dsort.1
|
|
@ -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;
|
||||
}
|
|
@ -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;
|
||||
}
|
||||
}
|
|
@ -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);
|
||||
}
|
|
@ -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>
|
|
@ -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
|
|
@ -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 / .
|
|
@ -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
|
|
@ -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.
|
|
@ -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 */
|
|
@ -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 *);
|
|
@ -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).
|
|
@ -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;
|
||||
}
|
|
@ -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.
|
||||
|
|
@ -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).
|
|
@ -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);
|
||||
}
|
||||
}
|
||||
}
|
|
@ -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
|
@ -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).
|
|
@ -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;
|
||||
}
|
|
@ -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.
|
||||
|
|
@ -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
|
|
@ -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);
|
||||
}
|
|
@ -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
|
|
@ -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
|
|
@ -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
|
|
@ -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
|
||||
|
|
@ -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
Loading…
Reference in New Issue
Block a user