Annotation of researchv10no/cmd/tail.c, revision 1.1

1.1     ! root        1: #include <ctype.h>
        !             2: #include <errno.h>
        !             3: #include <stdio.h>
        !             4: #include <libc/libc.h>
        !             5: 
        !             6: /* tail command, posix plus v10 option -r.
        !             7:    the simple command tail -c, legal in v10, is illegal */
        !             8: 
        !             9: long count;
        !            10: int anycount;
        !            11: int follow;
        !            12: int file = 0;
        !            13: enum { BEG, END } origin = END;
        !            14: enum { CHARS, LINES } units = LINES;
        !            15: enum { FWD, REV } dir = FWD;
        !            16: 
        !            17: extern void copy(void), keep(void), skip(void);
        !            18: extern void usage(void), reverse(void);
        !            19: extern void trunc(struct stat*, struct stat*);
        !            20: extern void suffix(char*), fatal(char*);
        !            21: extern long tseek(long, int);
        !            22: extern long tread(char*, long);
        !            23: extern void twrite(char*, long);
        !            24: extern int getnumber(char*);
        !            25: #define jump(o,p) tseek(o,p), copy()
        !            26: 
        !            27: main(int argc, char **argv)
        !            28: {
        !            29:        int seekable, c;
        !            30:        for(; argc>1&&((c=*argv[1])=='-'||c=='+'); argc--,argv++ ) {
        !            31:                if(getnumber(argv[1])) {
        !            32:                        suffix(argv[1]);
        !            33:                        continue;
        !            34:                } else if(c == '-')
        !            35:                        switch(argv[1][1]) {
        !            36:                        case 'c':
        !            37:                                units = CHARS;
        !            38:                        case 'n':
        !            39:                                if(getnumber(argv[1]+2))
        !            40:                                        continue;
        !            41:                                else if(argc>2&&getnumber(argv[2])) {
        !            42:                                        argc--, argv++;
        !            43:                                        continue;
        !            44:                                } else
        !            45:                                        usage();
        !            46:                        case 'r':
        !            47:                                dir = REV;
        !            48:                                continue;
        !            49:                        case 'f':
        !            50:                                follow++;
        !            51:                                continue;
        !            52:                        case '-':
        !            53:                                argc--, argv++;
        !            54:                        }
        !            55:                break;
        !            56:        }
        !            57:        if(dir==REV && (units==CHARS || follow || origin==BEG))
        !            58:                fatal("incompatible options");
        !            59:        if(!anycount)
        !            60:                count = dir==REV? ~0UL>>1: 10;
        !            61:        if(origin==BEG && units==LINES && count>0)
        !            62:                count--;
        !            63:        if(argc > 2)
        !            64:                usage();
        !            65:        if(argc > 1 && (file=open(argv[1],0)) < 0)
        !            66:                fatal(argv[1]);
        !            67:        seekable = lseek(file,0L,0) == 0;
        !            68:        errno = 0;
        !            69: 
        !            70:        if(!seekable && origin==END)
        !            71:                keep();
        !            72:        else if(!seekable && origin==BEG)
        !            73:                skip();
        !            74:        else if(units==CHARS && origin==END)
        !            75:                jump(-count, 2);
        !            76:        else if(units==CHARS && origin==BEG)
        !            77:                jump(count, 0);
        !            78:        else if(units==LINES && origin==END)
        !            79:                reverse();
        !            80:        else if(units==LINES && origin==BEG)
        !            81:                skip();
        !            82:        if(follow && seekable)
        !            83:                for(;;) {
        !            84:                        static struct stat sb0, sb1;
        !            85:                        trunc(&sb1, &sb0);
        !            86:                        copy();
        !            87:                        trunc(&sb0, &sb1);
        !            88:                        sleep(5);
        !            89:                }
        !            90:        return 0;
        !            91: }
        !            92: 
        !            93: void
        !            94: trunc(struct stat *old, struct stat *new)
        !            95: {
        !            96:        fstat(file, new);
        !            97:        if(new->st_size < old->st_size)
        !            98:                new->st_size = tseek(0L, 0);
        !            99: }
        !           100: 
        !           101: void
        !           102: suffix(char *s)
        !           103: {
        !           104:        while(*s && strchr("0123456789+-", *s))
        !           105:                s++;
        !           106:        switch(*s) {
        !           107:        case 'b':
        !           108:                if((count*=1024) < 0)
        !           109:                        fatal("too big");
        !           110:        case 'c':
        !           111:                units = CHARS;
        !           112:        case 'l':
        !           113:                s++;
        !           114:        }
        !           115:        switch(*s) {
        !           116:        case 'r':
        !           117:                dir = REV;
        !           118:                return;
        !           119:        case 'f':
        !           120:                follow++;
        !           121:                return;
        !           122:        case 0:
        !           123:                return;
        !           124:        }
        !           125:        usage();
        !           126: }
        !           127: 
        !           128: void
        !           129: skip(void)     /* read past head of the file to find tail */
        !           130: {
        !           131:        int i;
        !           132:        long n;
        !           133:        char buf[BUFSIZ];
        !           134:        if(units == CHARS) {
        !           135:                for( ; count>0; count -=n) {
        !           136:                        n = count<BUFSIZ? count: BUFSIZ;
        !           137:                        if(!(n = tread(buf, n)))
        !           138:                                return;
        !           139:                }
        !           140:        } else /*units == LINES*/ {
        !           141:                n = i = 0;
        !           142:                while(count > 0) {
        !           143:                        if(!(n = tread(buf, BUFSIZ)))
        !           144:                                return;
        !           145:                        for(i=0; i<n && count>0; i++)
        !           146:                                if(buf[i]=='\n')
        !           147:                                        count--;
        !           148:                }
        !           149:                twrite(buf+i, n-i);
        !           150:        }
        !           151:        copy();
        !           152: }
        !           153: 
        !           154: void
        !           155: copy(void)
        !           156: {
        !           157:        long n;
        !           158:        char buf[BUFSIZ];
        !           159:        while((n=tread(buf, BUFSIZ)) > 0) {
        !           160:                twrite(buf, n);
        !           161:                fflush(stdout); /* for FWD on pipe; else harmless */
        !           162:        }
        !           163: }
        !           164: 
        !           165: void
        !           166: keep(void)     /* read whole file, keeping the tail */
        !           167: {      /* complexity=length(file)*length(tail).  could be linear */
        !           168:        int len = 0;
        !           169:        long bufsiz = 0;
        !           170:        char *buf = 0;
        !           171:        int j, k, n;
        !           172:        for(n=1; n;) {
        !           173:                if(len+BUFSIZ > bufsiz) {
        !           174:                        bufsiz += 2*BUFSIZ;
        !           175:                        if(!(buf = realloc(buf, bufsiz+1)))
        !           176:                                fatal("out of space");
        !           177:                }
        !           178:                for( ; n && len<bufsiz; len+=n)
        !           179:                        n = tread(buf+len, bufsiz-len);
        !           180:                if(count >= len)
        !           181:                        continue;
        !           182:                if(units == CHARS)
        !           183:                        j = len - count;
        !           184:                else /*units == LINES*/ {
        !           185:                        j = buf[len-1]=='\n'? len-1: len;
        !           186:                        for(k=0; j>0; j--)
        !           187:                                if(buf[j-1] == '\n')
        !           188:                                        if(++k >= count)
        !           189:                                                break;
        !           190:                }
        !           191:                memmove(buf, buf+j, len-=j);
        !           192:        }
        !           193:        if(dir == REV) {
        !           194:                if(len>0 && buf[len-1]!='\n')
        !           195:                        buf[len++] = '\n';
        !           196:                for(j=len-1 ; j>0; j--)
        !           197:                        if(buf[j-1] == '\n') {
        !           198:                                twrite(buf+j, len-j);
        !           199:                                if(--count <= 0)
        !           200:                                        return;
        !           201:                                len = j;
        !           202:                        }
        !           203:        }
        !           204:        if(count > 0)
        !           205:                twrite(buf, len);
        !           206: }
        !           207: 
        !           208: void
        !           209: reverse(void)  /* count backward and print tail of file */
        !           210: {
        !           211:        int first;
        !           212:        long len = 0;
        !           213:        long n = 0;
        !           214:        long bufsiz = 0;
        !           215:        char *buf = 0;
        !           216:        long pos = tseek(0L, 2);
        !           217:        for(first=1; pos>0 && count>0; first=0) {
        !           218:                n = pos>BUFSIZ? BUFSIZ: (int)pos;
        !           219:                pos -= n;
        !           220:                if(len+n > bufsiz) {
        !           221:                        bufsiz += 2*BUFSIZ;
        !           222:                        if(!(buf = realloc(buf, bufsiz+1)))
        !           223:                                fatal("out of space");
        !           224:                }
        !           225:                memmove(buf+n, buf, len);
        !           226:                len += n;
        !           227:                tseek(pos, 0);
        !           228:                if(tread(buf, n) != n)
        !           229:                        fatal("length error");
        !           230:                if(first && buf[len-1]!='\n')
        !           231:                        buf[len++] = '\n';
        !           232:                for(n=len-1 ; n>0 && count>0; n--)
        !           233:                        if(buf[n-1] == '\n') {
        !           234:                                count--;
        !           235:                                if(dir == REV)
        !           236:                                        twrite(buf+n, len-n);
        !           237:                                len = n;
        !           238:                        }
        !           239:        }
        !           240:        if(dir == FWD) {
        !           241:                tseek(n==0? 0: pos+n+1, 0);
        !           242:                copy();
        !           243:        } else if(count > 0)
        !           244:                twrite(buf, len);
        !           245: }
        !           246: 
        !           247: long
        !           248: tseek(long o, int p)
        !           249: {
        !           250:        o = lseek(file, o, p);
        !           251:        if(o == -1)
        !           252:                fatal("");
        !           253:        return o;
        !           254: }
        !           255: 
        !           256: long
        !           257: tread(char *buf, long n)
        !           258: {
        !           259:        int r = read(file, buf, n);
        !           260:        if(r == -1)
        !           261:                fatal("");
        !           262:        return r;
        !           263: }
        !           264: 
        !           265: void
        !           266: twrite(char *s, long n)
        !           267: {
        !           268:        if(fwrite(s, 1 , n, stdout) != n)
        !           269:                fatal("");
        !           270: }
        !           271: 
        !           272: int
        !           273: getnumber(char *s)
        !           274: {
        !           275:        if(*s=='-' || *s=='+')
        !           276:                s++;
        !           277:        if(!isdigit(*s))
        !           278:                return 0;
        !           279:        if(s[-1] == '+')
        !           280:                origin = BEG;
        !           281:        if(anycount++)
        !           282:                fatal("excess option");
        !           283:        count = atol(s);
        !           284:        if(count < 0 ||         /* overflow */
        !           285:           (int)count != count) /* protect int args (read, fwrite) */
        !           286:                fatal("too big");
        !           287:        return 1;
        !           288: }      
        !           289: 
        !           290: void           
        !           291: fatal(char *s)
        !           292: {
        !           293:        write(2, "tail: ", 6);
        !           294:        if(errno)
        !           295:                perror(s);
        !           296:        else {
        !           297:                write(2, s, strlen(s));
        !           298:                write(2, "\n", 1);
        !           299:        }
        !           300:        exit(1);
        !           301: }
        !           302: 
        !           303: char *u = "usage: tail [-n N] [-c N] [-f] [-r] [+-N[bc][fr]] [file]\n";
        !           304: void
        !           305: usage(void)
        !           306: {
        !           307:        write(2, u, strlen(u));
        !           308:        exit(1);
        !           309: }

unix.superglobalmegacorp.com

This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.