Subversion Repositories planix.SVN

Rev

Rev 2 | Blame | Compare with Previous | Last modification | View Log | RSS feed

/*
 * Deal with duplicated lines in a file
 */
#include <u.h>
#include <libc.h>
#include <bio.h>
#include <ctype.h>

#define SIZE    8000

int     fields  = 0;
int     letters = 0;
int     linec   = 0;
char    mode;
int     uniq;
char    *b1, *b2;
long    bsize;
Biobuf  fin;
Biobuf  fout;

int     gline(char *buf);
void    pline(char *buf);
int     equal(char *b1, char *b2);
char*   skip(char *s);

void
main(int argc, char *argv[])
{
        int f;

        argv0 = argv[0];
        bsize = SIZE;
        b1 = malloc(bsize);
        b2 = malloc(bsize);
        f = 0;
        while(argc > 1) {
                if(*argv[1] == '-') {
                        if(isdigit(argv[1][1]))
                                fields = atoi(&argv[1][1]);
                        else
                                mode = argv[1][1];
                        argc--;
                        argv++;
                        continue;
                }
                if(*argv[1] == '+') {
                        letters = atoi(&argv[1][1]);
                        argc--;
                        argv++;
                        continue;
                }
                f = open(argv[1], 0);
                if(f < 0)
                        sysfatal("cannot open %s", argv[1]);
                break;
        }
        if(argc > 2)
                sysfatal("unexpected argument %s", argv[2]);
        Binit(&fin, f, OREAD);
        Binit(&fout, 1, OWRITE);

        if(gline(b1))
                exits(0);
        for(;;) {
                linec++;
                if(gline(b2)) {
                        pline(b1);
                        exits(0);
                }
                if(!equal(b1, b2)) {
                        pline(b1);
                        linec = 0;
                        do {
                                linec++;
                                if(gline(b1)) {
                                        pline(b2);
                                        exits(0);
                                }
                        } while(equal(b2, b1));
                        pline(b2);
                        linec = 0;
                }
        }
}

int
gline(char *buf)
{
        int len;
        char *p;

        p = Brdline(&fin, '\n');
        if(p == 0)
                return 1;
        len = Blinelen(&fin);
        if(len >= bsize-1)
                sysfatal("line too long");
        memmove(buf, p, len);
        buf[len-1] = 0;
        return 0;
}

void
pline(char *buf)
{
        switch(mode) {

        case 'u':
                if(uniq) {
                        uniq = 0;
                        return;
                }
                break;

        case 'd':
                if(uniq)
                        break;
                return;

        case 'c':
                Bprint(&fout, "%4d ", linec);
        }
        uniq = 0;
        Bprint(&fout, "%s\n", buf);
}

int
equal(char *b1, char *b2)
{
        char c;

        if(fields || letters) {
                b1 = skip(b1);
                b2 = skip(b2);
        }
        for(;;) {
                c = *b1++;
                if(c != *b2++) {
                        if(c == 0 && mode == 's')
                                return 1;
                        return 0;
                }
                if(c == 0) {
                        uniq++;
                        return 1;
                }
        }
}

char*
skip(char *s)
{
        int nf, nl;

        nf = nl = 0;
        while(nf++ < fields) {
                while(*s == ' ' || *s == '\t')
                        s++;
                while(!(*s == ' ' || *s == '\t' || *s == 0) ) 
                        s++;
        }
        while(nl++ < letters && *s != 0) 
                        s++;
        return s;
}