minix/commands/simple/uniq.c
2005-04-21 14:53:53 +00:00

196 lines
3.5 KiB
C
Executable file

/* uniq - compact repeated lines Author: John Woods */
/* Uniq [-udc] [-n] [+n] [infile [outfile]]
*
* Written 02/08/86 by John Woods, placed into public domain. Enjoy.
*
*/
/* If the symbol WRITE_ERROR is defined, uniq will exit(1) if it gets a
* write error on the output. This is not (of course) how V7 uniq does it,
* so undefine the symbol if you want to lose your output to a full disk
*/
#define WRITE_ERROR 1
#include <ctype.h>
#include <errno.h>
#include <string.h>
#include <stdlib.h>
#include <stdio.h>
char buffer[BUFSIZ];
int uflag = 1; /* default is union of -d and -u outputs */
int dflag = 1; /* flags are mutually exclusive */
int cflag = 0;
int fields = 0;
int chars = 0;
_PROTOTYPE(int main, (int argc, char **argv));
_PROTOTYPE(FILE *xfopen, (char *fn, char *mode));
_PROTOTYPE(char *skip, (char *s));
_PROTOTYPE(int equal, (char *s1, char *s2));
_PROTOTYPE(void show, (char *line, int count));
_PROTOTYPE(int uniq, (void));
_PROTOTYPE(void usage, (void));
_PROTOTYPE(int getline, (char *buf, int count));
FILE *xfopen(fn, mode)
char *fn, *mode;
{
FILE *p;
if ((p = fopen(fn, mode)) == NULL) {
perror("uniq");
fflush(stdout);
exit(1);
}
return(p);
}
int main(argc, argv)
int argc;
char *argv[];
{
char *p;
int inf = -1, outf;
setbuf(stdout, buffer);
for (--argc, ++argv; argc > 0 && (**argv == '-' || **argv == '+');
--argc, ++argv) {
if (**argv == '+')
chars = atoi(*argv + 1);
else if (isdigit(argv[0][1]))
fields = atoi(*argv + 1);
else if (argv[0][1] == '\0')
inf = 0; /* - is stdin */
else
for (p = *argv + 1; *p; p++) {
switch (*p) {
case 'd':
dflag = 1;
uflag = 0;
break;
case 'u':
uflag = 1;
dflag = 0;
break;
case 'c': cflag = 1; break;
default: usage();
}
}
}
/* Input file */
if (argc == 0)
inf = 0;
else if (inf == -1) { /* if - was not given */
fclose(stdin);
xfopen(*argv++, "r");
argc--;
}
if (argc == 0)
outf = 1;
else {
fclose(stdout);
xfopen(*argv++, "w");
argc--;
}
uniq();
fflush(stdout);
return(0);
}
char *skip(s)
char *s;
{
int n;
/* Skip fields */
for (n = fields; n > 0; --n) {
/* Skip blanks */
while (*s && (*s == ' ' || *s == '\t')) s++;
if (!*s) return s;
while (*s && (*s != ' ' && *s != '\t')) s++;
if (!*s) return s;
}
/* Skip characters */
for (n = chars; n > 0; --n) {
if (!*s) return s;
s++;
}
return s;
}
int equal(s1, s2)
char *s1, *s2;
{
return !strcmp(skip(s1), skip(s2));
}
void show(line, count)
char *line;
int count;
{
if (cflag)
printf("%4d %s", count, line);
else {
if ((uflag && count == 1) || (dflag && count != 1))
printf("%s", line);
}
}
/* The meat of the whole affair */
char *nowline, *prevline, buf1[1024], buf2[1024];
int uniq()
{
char *p;
int seen;
/* Setup */
prevline = buf1;
if (getline(prevline, 1024) < 0) return(0);
seen = 1;
nowline = buf2;
/* Get nowline and compare if not equal, dump prevline and swap
* pointers else continue, bumping seen count */
while (getline(nowline, 1024) > 0) {
if (!equal(prevline, nowline)) {
show(prevline, seen);
seen = 1;
p = nowline;
nowline = prevline;
prevline = p;
} else
seen += 1;
}
show(prevline, seen);
return 0;
}
void usage()
{
fprintf(stderr, "Usage: uniq [-udc] [+n] [-n] [input [output]]\n");
}
int getline(buf, count)
char *buf;
int count;
{
int c;
int ct = 0;
while (ct++ < count) {
c = getc(stdin);
if (c < 0) return(-1);
*buf++ = c;
if (c == '\n') {
*buf++ = 0;
return(ct);
}
}
return(ct);
}