diff --git a/bin/split/Makefile b/bin/split/Makefile new file mode 100644 index 0000000..1af1af4 --- /dev/null +++ b/bin/split/Makefile @@ -0,0 +1,13 @@ +# +# This makefile is intended for use with dmake(1) on Apple IIGS +# $Id: Makefile,v 1.1 1997/12/02 05:15:19 gdr Exp $ +# +# Created by Dave Tribby, November 1997 + +# Program name +PROG= split + +# Delivery directory +BINDIR = /usr/bin + +.INCLUDE : /src/gno/prog.mk diff --git a/bin/split/split.1 b/bin/split/split.1 new file mode 100644 index 0000000..3f6bb95 --- /dev/null +++ b/bin/split/split.1 @@ -0,0 +1,114 @@ +.\" Copyright (c) 1990, 1991, 1993, 1994 +.\" 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. +.\" +.\" @(#)split.1 8.3 (Berkeley) 4/16/94 +.\" +.TH SPLIT 1 "November 1997" "GNO" "Commands and Applications" +.SH NAME +.BR split +\- split a file into pieces +.SH SYNOPSIS +.BR split +.RB [ -b +.IR byte_count\c +.RB [ k | m ]] +.RB [ -l +.IR line_count ] +.RI [ file " [" name ]] +.PP +.I Obsolescent: +.PP +.BR split +.RB [ -\c +.IR line_count ] +.RI [ file " [" name ]] +.SH DESCRIPTION +The +.BR split +utility reads the given +.IR file +(or standard input if no file is specified) +and breaks it up into files of 1000 lines each. +.PP +The options are as follows: +.RS +.IP \fB-b\fR +Create smaller files +.IR byte_count +bytes in length. +If +.BR k +is appended to the number, the file is split into +.IR byte_count +kilobyte pieces. +If +.BR m +is appended to the number, the file is split into +.IR byte_count +megabyte pieces. +.IP \fB-l\fR +Create smaller files +.IR line_count +lines in length. +.RE +.PP +If additional arguments are specified, the first is used as the name +of the input file which is to be split. +If a second additional argument is specified, it is used as a prefix +for the names of the files into which the file is split. +In this case, each file into which the file is split is named by the +prefix followed by a lexically ordered suffix in the range of +.BR aa-zz . +.PP +If the +.IR name +argument is not specified, the file is split into lexically ordered +files named in the range of +.BR xaa - zzz . +.SH BUGS +For historical reasons, if you specify +.IR name , +.BR split +can only create 676 separate +files. +The default naming convention allows 2028 separate files. +.SH VERSION +This manual page documents +.BR split +version 2.0. +.SH ATTRIBUTIONS +This command was ported from FreeBSD source code +for distribution with GNO/ME 2.0.6. +.SH HISTORY +A version of +.BR split +written in 1992 was distributed with +earlier releases of GNO. diff --git a/bin/split/split.c b/bin/split/split.c new file mode 100644 index 0000000..54b3de2 --- /dev/null +++ b/bin/split/split.c @@ -0,0 +1,357 @@ +/* + * Copyright (c) 1987, 1993, 1994 + * 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. + */ + + +/* + * Modified for GNO (Apple IIGS) by Dave Tribby, November 1997 + * + * Constructs unacceptable to compiler are replaced using #ifndef __ORCAC__ + * + * Changes not related to compiler are replaced using #ifndef __GNO__ + * + * Added prototyped headers, surrounded by #ifndef __STDC__ + */ + + +#ifndef __GNO__ /* GNO doesn't use what strings */ +#ifndef lint +static const char copyright[] = +"@(#) Copyright (c) 1987, 1993, 1994\n\ + The Regents of the University of California. All rights reserved.\n"; +#endif /* not lint */ + +#ifndef lint +#if 0 +static char sccsid[] = "@(#)split.c 8.2 (Berkeley) 4/16/94"; +#endif +#endif /* not lint */ +#endif /* not GNO */ + +#include + +#include +#include +#include +#include +#include +#include +#include + +#define DEFLINE 1000 /* Default num lines per file. */ + +long bytecnt; /* Byte count to split on. */ +long numlines; /* Line count to split on. */ +int file_open; /* If a file open. */ +int ifd = -1, ofd = -1; /* Input/output file descriptors. */ +char bfr[MAXBSIZE]; /* I/O buffer. */ +char fname[MAXPATHLEN]; /* File name prefix. */ + +void newfile __P((void)); +void split1 __P((void)); +void split2 __P((void)); +static void usage __P((void)); + + +/* Interface to check on how much stack space a C program uses. */ +#if defined(__GNO__) && defined(__STACK_CHECK__) +#ifndef _GNO_GNO_H_ +#include +#endif +static void report_stack(void) +{ + fprintf(stderr,"\n ==> %d stack bytes used <== \n", _endStackCheck()); +} +#endif + + +int +#ifndef __STDC__ +main(argc, argv) + int argc; + char *argv[]; +#else +main (int argc, + char *argv[]) +#endif +{ + int ch; + char *ep, *p; + +#if defined(__GNO__) && defined(__STACK_CHECK__) + _beginStackCheck(); + atexit(report_stack); +#endif + while ((ch = getopt(argc, argv, "-0123456789b:l:")) != -1) + switch (ch) { + case '0': case '1': case '2': case '3': case '4': + case '5': case '6': case '7': case '8': case '9': + /* + * Undocumented kludge: split was originally designed + * to take a number after a dash. + */ + if (numlines == 0) { + p = argv[optind - 1]; + if (p[0] == '-' && p[1] == ch && !p[2]) + numlines = strtol(++p, &ep, 10); + else + numlines = + strtol(argv[optind] + 1, &ep, 10); + if (numlines <= 0 || *ep) + errx(1, "%s: illegal line count", optarg); + } + break; + case '-': /* Undocumented: historic stdin flag. */ + if (ifd != -1) + usage(); +#ifndef __GNO__ + ifd = 0; +#else + ifd = STDIN_FILENO; /* != 0 under GNO */ +#endif + break; + case 'b': /* Byte count. */ + if ((bytecnt = strtol(optarg, &ep, 10)) <= 0 || + (*ep != '\0' && *ep != 'k' && *ep != 'm')) + errx(1, "%s: illegal byte count", optarg); + if (*ep == 'k') + bytecnt *= 1024; + else if (*ep == 'm') + bytecnt *= 1048576; + break; + case 'l': /* Line count. */ + if (numlines != 0) + usage(); + if ((numlines = strtol(optarg, &ep, 10)) <= 0 || *ep) + errx(1, "%s: illegal line count", optarg); + break; + default: + usage(); + } +#ifndef __ORCAC__ + argv += optind; +#else + argv = argv + optind; +#endif + argc -= optind; + + if (*argv != NULL) + if (ifd == -1) { /* Input file. */ + if ((ifd = open(*argv, O_RDONLY, 0)) < 0) + err(1, "%s", *argv); + ++argv; + } + if (*argv != NULL) /* File name prefix. */ + (void)strcpy(fname, *argv++); + if (*argv != NULL) + usage(); + + if (numlines == 0) + numlines = DEFLINE; + else if (bytecnt) + usage(); + + if (ifd == -1) /* Stdin by default. */ +#ifndef __GNO__ + ifd = 0; +#else + ifd = STDIN_FILENO; /* != 0 under GNO */ +#endif + + if (bytecnt) { + split1(); + exit (0); + } + split2(); + exit(0); +} + +/* + * split1 -- + * Split the input by bytes. + */ +void +#ifndef __STDC__ +split1() +#else +split1(void) +#endif +{ + long bcnt; + int dist, len; + char *C; + + for (bcnt = 0;;) + switch (len = read(ifd, bfr, MAXBSIZE)) { + case 0: + exit(0); + case -1: + err(1, "read"); + /* NOTREACHED */ + default: + if (!file_open) { + newfile(); + file_open = 1; + } + if (bcnt + len >= bytecnt) { + dist = bytecnt - bcnt; + if (write(ofd, bfr, dist) != dist) + err(1, "write"); + len -= dist; + for (C = bfr + dist; len >= bytecnt; + len -= bytecnt, C += bytecnt) { + newfile(); + if (write(ofd, + C, (int)bytecnt) != bytecnt) + err(1, "write"); + } + if (len) { + newfile(); + if (write(ofd, C, len) != len) + err(1, "write"); + } else + file_open = 0; + bcnt = len; + } else { + bcnt += len; + if (write(ofd, bfr, len) != len) + err(1, "write"); + } + } +} + +/* + * split2 -- + * Split the input by lines. + */ +void +#ifndef __STDC__ +split2() +#else +split2(void) +#endif +{ + long lcnt; + int len, bcnt; + char *Ce, *Cs; + + for (lcnt = 0;;) + switch (len = read(ifd, bfr, MAXBSIZE)) { + case 0: + exit(0); + case -1: + err(1, "read"); + /* NOTREACHED */ + default: + if (!file_open) { + newfile(); + file_open = 1; + } + for (Cs = Ce = bfr; len--; Ce++) +#ifndef __GNO__ + if (*Ce == '\n' && ++lcnt == numlines) { +#else /* In GNO, \r is the line separator */ + if (*Ce == '\r' && ++lcnt == numlines) { +#endif + bcnt = Ce - Cs + 1; + if (write(ofd, Cs, bcnt) != bcnt) + err(1, "write"); + lcnt = 0; + Cs = Ce + 1; + if (len) + newfile(); + else + file_open = 0; + } + if (Cs < Ce) { + bcnt = Ce - Cs; + if (write(ofd, Cs, bcnt) != bcnt) + err(1, "write"); + } + } +} + +/* + * newfile -- + * Open a new output file. + */ +void +#ifndef __STDC__ +newfile() +#else +newfile(void) +#endif +{ + static long fnum; + static int defname; + static char *fpnt; + + if (ofd == -1) { + if (fname[0] == '\0') { + fname[0] = 'x'; + fpnt = fname + 1; + defname = 1; + } else { + fpnt = fname + strlen(fname); + defname = 0; + } + ofd = fileno(stdout); + } + /* + * Hack to increase max files; original code wandered through + * magic characters. Maximum files is 3 * 26 * 26 == 2028 + */ +#define MAXFILES 676 + if (fnum == MAXFILES) { + if (!defname || fname[0] == 'z') + errx(1, "too many files"); + ++fname[0]; + fnum = 0; + } + fpnt[0] = fnum / 26 + 'a'; + fpnt[1] = fnum % 26 + 'a'; + ++fnum; + if (!freopen(fname, "w", stdout)) + err(1, "%s", fname); +} + +static void +#ifndef __STDC__ +usage() +#else +usage(void) +#endif +{ + (void)fprintf(stderr, +"usage: split [-b byte_count] [-l line_count] [file [prefix]]\n"); + exit(1); +} diff --git a/bin/split/split.desc b/bin/split/split.desc new file mode 100644 index 0000000..bed83ad --- /dev/null +++ b/bin/split/split.desc @@ -0,0 +1,10 @@ +Name: split +Version: 2.0 (November 1997) +Shell: GNO +Author: Dave Tribby (from FreeBSD code) +Contact: tribby@cup.hp.com +Where: /bin +FTP: ground.isca.uiowa.edu apple2.caltech.edu trenco.myrias.com + + Split a file into pieces. + diff --git a/bin/split/split.rez b/bin/split/split.rez new file mode 100644 index 0000000..2df9a74 --- /dev/null +++ b/bin/split/split.rez @@ -0,0 +1,30 @@ +/* + * Resources for version and comment + * $Id: split.rez,v 1.1 1997/12/02 05:15:19 gdr Exp $ + */ +#define PROG "split" +#define DESC "Split a file into pieces." + +#include "Types.rez" + +/* + * Version + */ +resource rVersion (1, purgeable3) { + { 2, 0, 0, /* Version 2.0.0 */ + release, /* development|alpha|beta|final|release */ + 0 }, /* non-final release number */ + verUS, /* Country */ + PROG, /* Program name */ + DESC " Released with GNO/ME." +}; + + +/* + * Comment + */ +resource rComment (1, purgeable3) { + PROG " v2.0 (November 1997)\n" + "GNO utility: " DESC "\n" + "Ported from FreeBSD code by Dave Tribby." +}; diff --git a/bin/split/tests/dotests b/bin/split/tests/dotests new file mode 100644 index 0000000..8a99ff5 --- /dev/null +++ b/bin/split/tests/dotests @@ -0,0 +1,145 @@ +# Tests for split command; invoked by command file "fulltests" +# Written by Dave Tribby (November 1997) +# $Id: dotests,v 1.1 1997/12/02 05:15:26 gdr Exp $ + +# Location of the split command to be tested +set testcmd="../split" + +# Location of binary and ASCII files used in test +set bfile="$testcmd" +set afile="../split.c" + +# Location of sed command (used to strip unwanted blanks at end of echo) +set sedcmd="/src/gno/usr.bin/sed/sed" + +# Alias for rm command +alias rm "cp -p rm" + +# Record starting time +echo -n "Testing command $testcmd beginning at" +date + +set src="$afile" +set dest="x" +set cmp="/tmp/split.c" +set lines="1000" +echo "Splitting $src using defaults" +$testcmd < $src +echo " Completion status = $status" +cat ${dest}a? > $cmp +echo "Checking combined files against original (no differences expected)" +cmp $src $cmp +echo " Completion status = $status" +echo "" + +rm ${dest}a* $cmp + +set src="$afile" +set dest="/tmp/z" +set cmp="/tmp/split.c" +set lines="100" +echo "Splitting $src into $lines line pieces" +$testcmd -l $lines $src $dest +echo " Completion status = $status" +cat /tmp/z* > $cmp +echo "Checking combined files against original (no differences expected)" +cmp $src $cmp +echo " Completion status = $status" +echo "Checking length of file against requested length" +set count="/tmp/count" +cat ${dest}aa | wc -l > $count +echo " $lines" | $sedcmd -e's/ *$//' > ${count}2 +cmp $count ${count}2 +echo " Completion status = $status" +echo "" + +rm ${dest}* $cmp $count ${count}2 + +set src="$bfile" +set dest="/tmp/z" +set cmp="/tmp/split" +set chars="3500" +echo "Splitting $src into $chars character pieces" +$testcmd -b $chars $src $dest +echo " Completion status = $status" +cat /tmp/z* > $cmp +echo "Checking combined files against original (no differences expected)" +cmp $src $cmp +echo " Completion status = $status" +echo "Checking length of file against requested length" +set count="/tmp/count" +cat ${dest}aa | wc -c > $count +echo " $chars" | $sedcmd -e's/ *$//' > ${count}2 +cmp $count ${count}2 +echo " Completion status = $status" +echo "" + +rm ${dest}* $cmp $count ${count}2 + +set src="$bfile" +set dest="/tmp/z" +set cmp="/tmp/split" +set numk="4" +set chars="4096" +echo "Splitting $src into ${numk}K character pieces" +$testcmd -b ${numk}k $src $dest +echo " Completion status = $status" +cat /tmp/z* > $cmp +echo "Checking combined files against original (no differences expected)" +cmp $src $cmp +echo " Completion status = $status" +echo "Checking length of file against requested length" +set count="/tmp/count" +cat ${dest}aa | wc -c > $count +echo " $chars" | $sedcmd -e's/ *$//' > ${count}2 +cmp $count ${count}2 +echo " Completion status = $status" +echo "" + +rm ${dest}* $cmp $count ${count}2 + +set src="$afile" +set dest="/tmp/z" +set cmp="/tmp/split.c" +set lines="100" +echo "Splitting $src into $lines line pieces (obsolescent)" +$testcmd -$lines $src $dest +echo " Completion status = $status" +cat /tmp/z* > $cmp +echo "Checking combined files against original (no differences expected)" +cmp $src $cmp +echo " Completion status = $status" +echo "Checking length of file against requested length" +set count="/tmp/count" +cat ${dest}aa | wc -l > $count +echo " $lines" | $sedcmd -e's/ *$//' > ${count}2 +cmp $count ${count}2 +echo " Completion status = $status" +echo "" + + + +echo "***** Error Messages *****" + +set dest="/tmp/err.cond" + +echo "" +echo "Expected error: illegal option" +$testcmd -x $src > $dest +echo " Error completion status = $status (expected: 1)" + +echo "" +echo "Expected error: illegal byte count" +$testcmd -b 12x $src > $dest +echo " Error completion status = $status (expected: 1)" + +echo "" +echo "Expected error: illegal line count" +$testcmd -l 12x $src > $dest +echo " Error completion status = $status (expected: 1)" + +echo "" +set src="badname" +echo "Expected error: $src: no such file or directory" +$testcmd $src > $dest +echo " Error completion status = $status (expected: 1)" diff --git a/bin/split/tests/fulltests b/bin/split/tests/fulltests new file mode 100644 index 0000000..4e63602 --- /dev/null +++ b/bin/split/tests/fulltests @@ -0,0 +1,29 @@ +# gsh script to run tests and collect results +# Written by Dave Tribby * August 1997 +# $Id: fulltests,v 1.1 1997/12/02 05:15:26 gdr Exp $ + +# Name of gsh script containing test cases +set command="dotests" +# Sometimes the file type is modified by editing; make it executable +chtyp -l exec $command + +# Filenames for raw and modified results +set raw_file="/tmp/rawlist" +set result_file="test.list" + +# Location of tr command that knows how to handle classes +set trcmd="/src/gno/usr.bin/tr/tr" + +# --- Begin the tests --- + +echo -n "Executing test script \"$command\" from directory " +pwd + +# Create a new gsh invocation and record all I/O +echo "$command ; exit" | script $raw_file + +# Cleanup control chars using either of the following... +echo "Done with tests. Removing control characters from results file" +$trcmd -c -ds '[:print:]\r' '\r' < $raw_file > $result_file + +echo "Tests results have been saved as \"$result_file\"" diff --git a/bin/uniq/Makefile b/bin/uniq/Makefile new file mode 100644 index 0000000..eb82540 --- /dev/null +++ b/bin/uniq/Makefile @@ -0,0 +1,13 @@ +# +# This makefile is intended for use with dmake(1) on Apple IIGS +# $Id: Makefile,v 1.1 1997/12/02 05:15:26 gdr Exp $ +# +# Created by Dave Tribby, November 1997 + +# Program name +PROG= uniq + +# Delivery directory +BINDIR = /usr/bin + +.INCLUDE : /src/gno/prog.mk diff --git a/bin/uniq/tests/dotests b/bin/uniq/tests/dotests new file mode 100644 index 0000000..0225397 --- /dev/null +++ b/bin/uniq/tests/dotests @@ -0,0 +1,145 @@ +# Tests for uniq command; invoked by command file "fulltests" +# Written by Dave Tribby (November 1997) +# $Id: dotests,v 1.1 1997/12/02 05:15:26 gdr Exp $ + +# Location of the uniq command to be tested +set testcmd="../uniq" + +# Record starting time +echo -n "Testing command $testcmd beginning at" +date + +set src="in.file" +set cmp="ulines" +set dest="/tmp/$cmp" +echo "Unique lines past column 27 in $src" +cat $src | $testcmd -s 27 > $dest +echo " Completion status = $status" +echo "Checking results against control file $cmp (no differences expected)" +cmp $cmp $dest +echo " Completion status = $status" +echo "" + +set cmp="uclines" +set dest="/tmp/${cmp}A" +echo "Unique lines past column 27 with count in $src" +$testcmd -c -s 27 < $src > $dest +echo " Completion status = $status" +echo "Checking results against control file $cmp (no differences expected)" +cmp $cmp $dest +echo " Completion status = $status" +echo "" + +set dest="/tmp/${cmp}B" +echo "Unique lines past field 4 with count in $src" +$testcmd -c -f 4 $src > $dest +echo " Completion status = $status" +echo "Checking results against control file $cmp (no differences expected)" +cmp $cmp $dest +echo " Completion status = $status" +echo "" + +set dest="/tmp/${cmp}C" +echo "Unique lines past column 27 with count (obsolescent) in $src" +$testcmd -c +27 < $src > $dest +echo " Completion status = $status" +echo "Checking results against control file $cmp (no differences expected)" +cmp $cmp $dest +echo " Completion status = $status" +echo "" + +set dest="/tmp/${cmp}D" +echo "Unique lines past field 4 with count (obsolescent) in $src" +$testcmd -c -4 $src > $dest +echo " Completion status = $status" +echo "Checking results against control file $cmp (no differences expected)" +cmp $cmp $dest +echo " Completion status = $status" +echo "" + +set src="in.file.shift" +set dest="/tmp/${cmp}E" +echo "Unique lines past field 4, shifted, with count in $src" +$testcmd -c -i -f 4 $src > $dest +echo " Completion status = $status" +echo "Checking results against control file $cmp (no differences expected)" +cmp $cmp $dest +echo " Completion status = $status" +echo "" + +set src="in.file" +set cmp="nuclines" +set dest="/tmp/${cmp}A" +echo "Unique lines past column 25 with count in $src" +$testcmd -c -s 25 < $src > $dest +echo " Completion status = $status" +echo "Checking results against control file $cmp (no differences expected)" +cmp $cmp $dest +echo " Completion status = $status" +echo "" + +set dest="/tmp/${cmp}B" +echo "Unique lines past field 3 with count in $src" +$testcmd -c -f 3 $src > $dest +echo " Completion status = $status" +echo "Checking results against control file $cmp (no differences expected)" +cmp $cmp $dest +echo " Completion status = $status" +echo "" + +set cmp="uulines" +set dest="/tmp/${cmp}" +echo "Unique lines past column 27, excluding repeated, in $src" +$testcmd -u -s 27 $src $dest +echo " Completion status = $status" +echo "Checking results against control file $cmp (no differences expected)" +cmp $cmp $dest +echo " Completion status = $status" +echo "" + +set cmp="udlines" +set dest="/tmp/${cmp}" +echo "Unique lines past column 27, excluding unrepeated, in $src" +$testcmd -d -s 27 $src $dest +echo " Completion status = $status" +echo "Checking results against control file $cmp (no differences expected)" +cmp $cmp $dest +echo " Completion status = $status" +echo "" + +set src="in.file.shift" +set cmp="udlines" +set dest="/tmp/${cmp}A" +echo "Unique lines past column 27, shifted, excluding unrepeated, in $src" +$testcmd -d -i -s 27 $src $dest +echo " Completion status = $status" +echo "Checking results against control file $cmp (no differences expected)" +cmp $cmp $dest +echo " Completion status = $status" +echo "" + + +echo "***** Error Messages *****" + +set dest="/tmp/err.cond" + +echo "" +echo "Expected error: illegal option" +$testcmd -x $src $dest +echo " Error completion status = $status (expected: 1)" + +echo "" +echo "Expected error: illegal combination of options (usage printed)" +$testcmd -c -d $src $dest +echo " Error completion status = $status (expected: 1)" + +echo "" +echo "Expected error: illegal combination of options (usage printed)" +$testcmd -c -u $src $dest +echo " Error completion status = $status (expected: 1)" + +echo "" +set src="badname" +echo "Expected error: $src: no such file or directory" +$testcmd $src > $dest +echo " Error completion status = $status (expected: 1)" diff --git a/bin/uniq/tests/fulltests b/bin/uniq/tests/fulltests new file mode 100644 index 0000000..4e63602 --- /dev/null +++ b/bin/uniq/tests/fulltests @@ -0,0 +1,29 @@ +# gsh script to run tests and collect results +# Written by Dave Tribby * August 1997 +# $Id: fulltests,v 1.1 1997/12/02 05:15:26 gdr Exp $ + +# Name of gsh script containing test cases +set command="dotests" +# Sometimes the file type is modified by editing; make it executable +chtyp -l exec $command + +# Filenames for raw and modified results +set raw_file="/tmp/rawlist" +set result_file="test.list" + +# Location of tr command that knows how to handle classes +set trcmd="/src/gno/usr.bin/tr/tr" + +# --- Begin the tests --- + +echo -n "Executing test script \"$command\" from directory " +pwd + +# Create a new gsh invocation and record all I/O +echo "$command ; exit" | script $raw_file + +# Cleanup control chars using either of the following... +echo "Done with tests. Removing control characters from results file" +$trcmd -c -ds '[:print:]\r' '\r' < $raw_file > $result_file + +echo "Tests results have been saved as \"$result_file\"" diff --git a/bin/uniq/tests/in.file b/bin/uniq/tests/in.file new file mode 100644 index 0000000..0598dd5 --- /dev/null +++ b/bin/uniq/tests/in.file @@ -0,0 +1,11 @@ +total 91k +erw-brd 0000 txt 947 Nov 19 +drw-brd 0000 DIR 512 Nov 19 +erwxbrd 0100 exe 64403 Nov 19 +erw-brd 0000 txt 5396 Nov 20 +erw-brd 0008 src 8099 Nov 19 +erw-brd 0015 src 990 Nov 19 +-rw-brd 0000 obj 11543 Nov 19 +erwxbrd 0000 s16 702 Nov 19 +erw-brd 0015 src 1324 Nov 19 +-rw-brd 0000 obj 226 Nov 19 diff --git a/bin/uniq/tests/in.file.shift b/bin/uniq/tests/in.file.shift new file mode 100644 index 0000000..f49cf9a --- /dev/null +++ b/bin/uniq/tests/in.file.shift @@ -0,0 +1,11 @@ +total 91k +erw-brd 0000 txt 947 Nov 19 +drw-brd 0000 DIR 512 NOV 19 +erwxbrd 0100 exe 64403 Nov 19 +erw-brd 0000 txt 5396 Nov 20 +erw-brd 0008 src 8099 Nov 19 +erw-brd 0015 src 990 NOV 19 +-rw-brd 0000 obj 11543 Nov 19 +erwxbrd 0000 s16 702 NOV 19 +erw-brd 0015 src 1324 Nov 19 +-rw-brd 0000 obj 226 NOV 19 diff --git a/bin/uniq/tests/nuclines b/bin/uniq/tests/nuclines new file mode 100644 index 0000000..6d81f86 --- /dev/null +++ b/bin/uniq/tests/nuclines @@ -0,0 +1,11 @@ + 1 total 91k + 1 erw-brd 0000 txt 947 Nov 19 + 1 drw-brd 0000 DIR 512 Nov 19 + 1 erwxbrd 0100 exe 64403 Nov 19 + 1 erw-brd 0000 txt 5396 Nov 20 + 1 erw-brd 0008 src 8099 Nov 19 + 1 erw-brd 0015 src 990 Nov 19 + 1 -rw-brd 0000 obj 11543 Nov 19 + 1 erwxbrd 0000 s16 702 Nov 19 + 1 erw-brd 0015 src 1324 Nov 19 + 1 -rw-brd 0000 obj 226 Nov 19 diff --git a/bin/uniq/tests/uclines b/bin/uniq/tests/uclines new file mode 100644 index 0000000..2fe063a --- /dev/null +++ b/bin/uniq/tests/uclines @@ -0,0 +1,4 @@ + 1 total 91k + 3 erw-brd 0000 txt 947 Nov 19 + 1 erw-brd 0000 txt 5396 Nov 20 + 6 erw-brd 0008 src 8099 Nov 19 diff --git a/bin/uniq/tests/udlines b/bin/uniq/tests/udlines new file mode 100644 index 0000000..b5c4aa4 --- /dev/null +++ b/bin/uniq/tests/udlines @@ -0,0 +1,2 @@ +erw-brd 0000 txt 947 Nov 19 +erw-brd 0008 src 8099 Nov 19 diff --git a/bin/uniq/tests/ulines b/bin/uniq/tests/ulines new file mode 100644 index 0000000..6023933 --- /dev/null +++ b/bin/uniq/tests/ulines @@ -0,0 +1,4 @@ +total 91k +erw-brd 0000 txt 947 Nov 19 +erw-brd 0000 txt 5396 Nov 20 +erw-brd 0008 src 8099 Nov 19 diff --git a/bin/uniq/tests/uulines b/bin/uniq/tests/uulines new file mode 100644 index 0000000..c717a2e --- /dev/null +++ b/bin/uniq/tests/uulines @@ -0,0 +1,2 @@ +total 91k +erw-brd 0000 txt 5396 Nov 20 diff --git a/bin/uniq/uniq.1 b/bin/uniq/uniq.1 new file mode 100644 index 0000000..ff87f86 --- /dev/null +++ b/bin/uniq/uniq.1 @@ -0,0 +1,141 @@ +.\" Copyright (c) 1991, 1993 +.\" The 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. +.\" +.\" From: @(#)uniq.1 8.1 (Berkeley) 6/6/93 +.\" $Id: uniq.1,v 1.1 1997/12/02 05:15:26 gdr Exp $ +.\" +.TH UNIQ 1 "November 1997" "GNO" "Commands and Applications" +.SH NAME +.BR uniq +\- report or filter out repeated lines in a file +.SH SYNOPSIS +.BR uniq +.RB [ -c " | " -du ] +.RB [ -i ] +.RB [ -f +.IR fields ] +.RB [ -s +.IR chars ] +.RI [ input +.RI [ output "]]" +.PP +.I Obsolescent: +.PP +.BR uniq " [\c" +.BI - fields\c +.RI "] [\c" +.BI + chars\c +.RI "] [" input +.RI [ output "]]" +.SH DESCRIPTION +The +.BR uniq +utility reads the standard input comparing adjacent lines, and writes +a copy of each unique input line to the standard output. +The second and succeeding copies of identical adjacent input lines are +not written. +Repeated lines in the input will not be detected if they are not adjacent, +so it may be necessary to sort the files first. +.PP +The following options are available: +.RS +.IP \fB-c\fR +Precede each output line with the count of the number of times the line +occurred in the input, followed by a single space. +.IP \fB-d\fR +Print one copy of each repeated line in the input. +.IP "\fB-f\fR \fIfields\fR" +Ignore the first +.IR fields +in each input line when doing comparisons. +A field is a string of non-blank characters separated from adjacent fields +by blanks. +Field numbers are one based, i.e. the first field is field one. +.IP "\fB-s\fR \fIchars\fR" +Ignore the first +.IR chars +characters in each input line when doing comparisons. +If specified in conjunction with the +.BR -f +option, the first +.IR chars +characters after the first +.IR fields +fields will be ignored. +Character numbers are one based, i.e. the first character is character one. +.IP \fB-u\fR +Print lines that are not repeated in the input. +.IP \fB-i\fR +Case insensitive comparison of lines. +.RE +.PP +If additional arguments are specified on the command line, the first +such argument is used as the name of an input file, the second is used +as the name of an output file. +.PP +If neither of the options +.BR d " or " u +are specified on the command line, +.BR uniq +behaves as if both +.BR d " and " u +are set, printing a single copy of repeated lines as well as unrepeated lines. +.PP +The +.BR uniq +utility exits 0 on success, and >0 if an error occurs. +.SH COMPATIBILITY +The historic +.BI + number +and +.BI - number +options have been deprecated but are still supported in this implementation. +.SH VERSION +This manual page documents +.BR uniq +version 2.0. +.SH ATTRIBUTIONS +This command was ported from FreeBSD source code +for distribution with GNO/ME 2.0.6. +.SH HISTORY +A version of +.BR uniq +written in 1992 was distributed with +earlier releases of GNO. +.SH SEE ALSO +.BR sort (1) +.SH STANDARDS +The +.BR uniq +utility is expected to be POSIX-2 compatible. diff --git a/bin/uniq/uniq.c b/bin/uniq/uniq.c new file mode 100644 index 0000000..3feb3af --- /dev/null +++ b/bin/uniq/uniq.c @@ -0,0 +1,336 @@ +/* + * Copyright (c) 1989, 1993 + * The Regents of the University of California. All rights reserved. + * + * This code is derived from software contributed to Berkeley by + * Case Larsen. + * + * 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. + */ + + +/* + * Modified for GNO (Apple IIGS) by Dave Tribby, November 1997 + * + * Constructs unacceptable to compiler are replaced using #ifndef __ORCAC__ + * + * Changes not related to compiler are replaced using #ifndef __GNO__ + * + * Added prototyped headers, surrounded by #ifndef __STDC__ + */ + + +#ifndef __GNO__ /* GNO doesn't use what strings */ +#ifndef lint +static const char copyright[] = +"@(#) Copyright (c) 1989, 1993\n\ + The Regents of the University of California. All rights reserved.\n"; +#endif /* not lint */ + +#ifndef lint +#if 0 +static char sccsid[] = "@(#)uniq.c 8.3 (Berkeley) 5/4/95"; +#endif +static const char rcsid[] = + "$Id: uniq.c,v 1.1 1997/12/02 05:15:26 gdr Exp $"; +#endif /* not lint */ +#endif /* not GNO */ + +#include +#include +#include +#include +#include +#include + +#define MAXLINELEN (8 * 1024) + +int cflag, dflag, uflag; +int numchars, numfields, repeats; + +FILE *file __P((char *, char *)); +void show __P((FILE *, char *)); +char *skip __P((char *)); +void obsolete __P((char *[])); +static void usage __P((void)); + + +/* Interface to check on how much stack space a C program uses. */ +#if defined(__GNO__) && defined(__STACK_CHECK__) +#ifndef _GNO_GNO_H_ +#include +#endif +static void report_stack(void) +{ + fprintf(stderr,"\n ==> %d stack bytes used <== \n", _endStackCheck()); +} +#endif + + +int +#ifndef __STDC__ +main (argc, argv) + int argc; + char *argv[]; +#else +main (int argc, + char *argv[]) +#endif +{ + register char *t1, *t2; + FILE *ifp, *ofp; + int ch; + char *prevline, *thisline, *p; +#ifndef __ORCAC__ + int iflag = 0, comp; +#else /* "comp" is a floating point type in ORCA/C */ + int iflag = 0, compr; +#endif + +#if defined(__GNO__) && defined(__STACK_CHECK__) + _beginStackCheck(); + atexit(report_stack); +#endif + obsolete(argv); + while ((ch = getopt(argc, argv, "-cdif:s:u")) != -1) + switch (ch) { + case '-': + --optind; + goto done; + case 'c': + cflag = 1; + break; + case 'd': + dflag = 1; + break; + case 'i': + iflag = 1; + break; + case 'f': + numfields = strtol(optarg, &p, 10); + if (numfields < 0 || *p) + errx(1, "illegal field skip value: %s", optarg); + break; + case 's': + numchars = strtol(optarg, &p, 10); + if (numchars < 0 || *p) + errx(1, "illegal character skip value: %s", optarg); + break; + case 'u': + uflag = 1; + break; + case '?': + default: + usage(); + } + +done: argc -= optind; +#ifndef __ORCAC__ + argv +=optind; +#else + argv = argv + optind; +#endif + + /* If no flags are set, default is -d -u. */ + if (cflag) { + if (dflag || uflag) + usage(); + } else if (!dflag && !uflag) + dflag = uflag = 1; + + switch(argc) { + case 0: + ifp = stdin; + ofp = stdout; + break; + case 1: + ifp = file(argv[0], "r"); + ofp = stdout; + break; + case 2: + ifp = file(argv[0], "r"); + ofp = file(argv[1], "w"); + break; + default: + usage(); + } + + prevline = malloc(MAXLINELEN); + thisline = malloc(MAXLINELEN); + if (prevline == NULL || thisline == NULL) + errx(1, "malloc"); + + if (fgets(prevline, MAXLINELEN, ifp) == NULL) + exit(0); + + while (fgets(thisline, MAXLINELEN, ifp)) { + /* If requested get the chosen fields + character offsets. */ + if (numfields || numchars) { + t1 = skip(thisline); + t2 = skip(prevline); + } else { + t1 = thisline; + t2 = prevline; + } + + /* If different, print; set previous to new value. */ + if (iflag) +#ifndef __ORCAC__ + comp = strcasecmp(t1, t2); + else + comp = strcmp(t1, t2); + + if (comp) { +#else + compr = strcasecmp(t1, t2); + else + compr = strcmp(t1, t2); + + if (compr) { +#endif + show(ofp, prevline); + t1 = prevline; + prevline = thisline; + thisline = t1; + repeats = 0; + } else + ++repeats; + } + show(ofp, prevline); + exit(0); +} + +/* + * show -- + * Output a line depending on the flags and number of repetitions + * of the line. + */ +void +#ifndef __STDC__ +show(ofp, str) + FILE *ofp; + char *str; +#else +show( FILE *ofp, + char *str) +#endif +{ + + if (cflag && *str) + (void)fprintf(ofp, "%4d %s", repeats + 1, str); + if ((dflag && repeats) || (uflag && !repeats)) + (void)fprintf(ofp, "%s", str); +} + +char * +#ifndef __STDC__ +skip(str) + register char *str; +#else +skip(register char *str) +#endif +{ + register int infield, nchars, nfields; + + for (nfields = numfields, infield = 0; nfields && *str; ++str) + if (isspace(*str)) { + if (infield) { + infield = 0; + --nfields; + } + } else if (!infield) + infield = 1; + for (nchars = numchars; nchars-- && *str; ++str); + return(str); +} + +FILE * +#ifndef __STDC__ +file(name, mode) + char *name, *mode; +#else +file(char *name, char *mode) +#endif +{ + FILE *fp; + + if ((fp = fopen(name, mode)) == NULL) + err(1, "%s", name); + return(fp); +} + +void +#ifndef __STDC__ +obsolete(argv) + char *argv[]; +#else +obsolete(char *argv[]) +#endif +{ + int len; + char *ap, *p, *start; + + while ((ap = *++argv)) { + /* Return if "--" or not an option of any form. */ + if (ap[0] != '-') { + if (ap[0] != '+') + return; + } else if (ap[1] == '-') + return; + if (!isdigit(ap[1])) + continue; + /* + * Digit signifies an old-style option. Malloc space for dash, + * new option and argument. + */ + len = strlen(ap); + if ((start = p = malloc(len + 3)) == NULL) + errx(1, "malloc"); + *p++ = '-'; + *p++ = ap[0] == '+' ? 's' : 'f'; + (void)strcpy(p, ap + 1); + *argv = start; + } +} + +static void +#ifndef __STDC__ +usage() +#else +usage(void) +#endif +{ + (void)fprintf(stderr, +#ifndef __GNO__ + "usage: uniq [-c | -du | -i] [-f fields] [-s chars] [input [output]]\n"); +#else + "usage: uniq [-c | -du] [-i] [-f fields] [-s chars] [input [output]]\n"); +#endif + exit(1); +} diff --git a/bin/uniq/uniq.desc b/bin/uniq/uniq.desc new file mode 100644 index 0000000..b369d51 --- /dev/null +++ b/bin/uniq/uniq.desc @@ -0,0 +1,9 @@ +Name: uniq +Version: 2.0 (November 1997) +Shell: GNO +Author: Dave Tribby (from FreeBSD code) +Contact: tribby@cup.hp.com +Where: /bin +FTP: ground.isca.uiowa.edu apple2.caltech.edu trenco.myrias.com + + report or filter out repeated lines in a file diff --git a/bin/uniq/uniq.rez b/bin/uniq/uniq.rez new file mode 100644 index 0000000..cd36656 --- /dev/null +++ b/bin/uniq/uniq.rez @@ -0,0 +1,30 @@ +/* + * Resources for version and comment + * $Id: uniq.rez,v 1.1 1997/12/02 05:15:26 gdr Exp $ + */ +#define PROG "uniq" +#define DESC "Report or filter out repeated lines in a file." + +#include "Types.rez" + +/* + * Version + */ +resource rVersion (1, purgeable3) { + { 2, 0, 0, /* Version 2.0.0 */ + release, /* development|alpha|beta|final|release */ + 0 }, /* non-final release number */ + verUS, /* Country */ + PROG, /* Program name */ + DESC " Released with GNO/ME." +}; + + +/* + * Comment + */ +resource rComment (1, purgeable3) { + PROG " v2.0 (November 1997)\n" + "GNO utility: " DESC "\n" + "Ported from FreeBSD code by Dave Tribby." +};