Introduction
Introduction Statistics Contact Development Disclaimer Help
merge - 9base - revived minimalist port of Plan 9 userland to Unix
git clone git://git.suckless.org/9base
Log
Files
Refs
README
LICENSE
---
commit 7dce804fe658181cb8cbb102a525ca34b4fb0006
parent a7102135eff7e934b6616a59dcb83c09bf188f06
Author: Anselm R Garbe <[email protected]>
Date: Tue, 27 Apr 2010 14:48:07 +0000
merge
Diffstat:
M .hgtags | 1 +
M LICENSE | 2 +-
M Makefile | 2 +-
M README | 2 +-
M config.mk | 4 ++--
M fortune/fortune.1 | 23 +++++++++++++++++++++++
M freq/freq.1 | 40 +++++++++++++++++++++++++++++…
M mkdir/mkdir.1 | 43 ++++++++++++++++++++++++++++++
D tac/Makefile | 10 ----------
D tac/tac.1 | 28 ----------------------------
D tac/tac.c | 60 -----------------------------…
A tail/Makefile | 11 +++++++++++
A tail/tail.1 | 87 +++++++++++++++++++++++++++++…
A tail/tail.c | 363 +++++++++++++++++++++++++++++…
14 files changed, 573 insertions(+), 103 deletions(-)
---
diff --git a/.hgtags b/.hgtags
@@ -2,3 +2,4 @@
538338114742f2e81f6c52a5a323bdf7ca0d5d86 2
7c1decda5b50405d3b62daa8369aa24c82e7b615 3
25d1757fba6bcef82866bad87dcff6f2333673cc 4
+5f3d19e583ff4504cbc6247b711e728bd602d6f2 5
diff --git a/LICENSE b/LICENSE
@@ -2,7 +2,7 @@ The rare bits touched by Anselm R. Garbe are under following LI…
MIT/X Consortium License
-(C)opyright 2005-2009 Anselm R. Garbe <garbeam at gmail dot com>
+© 2005-2010 Anselm R Garbe <[email protected]>
Permission is hereby granted, free of charge, to any person obtaining a
copy of this software and associated documentation files (the "Software"),
diff --git a/Makefile b/Makefile
@@ -4,7 +4,7 @@ include config.mk
SUBDIRS = lib9 yacc awk basename bc cal cat cleanname date dc du echo \
fortune freq getflags grep hoc ls mk mkdir mtime rc read \
- sed seq sleep sort tac tee test touch tr troff uniq
+ sed seq sleep sort tail tee test touch tr troff uniq
# factor primes
diff --git a/README b/README
@@ -21,4 +21,4 @@ References
----------
[1] http://swtch.com/plan9port/
---Anselm R. Garbe
+--Anselm R Garbe
diff --git a/config.mk b/config.mk
@@ -5,9 +5,9 @@ PREFIX = /usr/local/plan9
MANPREFIX = ${PREFIX}/share/man
VERSION = 5
-#OBJTYPE = 386
+OBJTYPE = 386
#OBJTYPE = arm
-OBJTYPE = x86_64
+#OBJTYPE = x86_64
# Linux/BSD
#CFLAGS += -Wall -Wno-missing-braces -Wno-parentheses -Wno-switch -c -I. …
diff --git a/fortune/fortune.1 b/fortune/fortune.1
@@ -0,0 +1,23 @@
+.TH FORTUNE 1
+.SH NAME
+fortune \- sample lines from a file
+.SH SYNOPSIS
+.B fortune
+[
+.I file
+]
+.SH DESCRIPTION
+.I Fortune
+prints a one-line aphorism chosen at random.
+If a
+.I file
+is specified, the saying is taken from that file;
+otherwise it is selected from
+.BR \*9/lib/fortunes .
+.SH FILES
+.B \*9/lib/fortunes
+.br
+.B \*9/lib/fortunes.index
+\ \ fast lookup table, maintained automatically
+.SH SOURCE
+.B \*9/src/cmd/fortune.c
diff --git a/freq/freq.1 b/freq/freq.1
@@ -0,0 +1,40 @@
+.TH FREQ 1
+.SH NAME
+freq \- print histogram of character frequencies
+.SH SYNOPSIS
+.B freq
+[
+.B -dxocr
+]
+[
+.I file ...
+]
+.SH DESCRIPTION
+.I Freq
+reads the given files (default standard input)
+and prints histograms of the character frequencies.
+By default,
+.I freq
+counts each byte as a character;
+under the
+.B -r
+option it instead counts
+.SM UTF
+sequences, that is, runes.
+.PP
+Each non-zero entry of the table is printed preceded by the byte value,
+in decimal, octal, hex, and
+Unicode
+character (if printable).
+If any options are given, the
+.BR -d ,
+.BR -x ,
+.BR -o ,
+.B -c
+flags specify a subset of value formats: decimal, hex, octal, and
+character, respectively.
+.SH SOURCE
+.B \*9/src/cmd/freq.c
+.SH SEE ALSO
+.IR utf (7),
+.IR wc (1)
diff --git a/mkdir/mkdir.1 b/mkdir/mkdir.1
@@ -0,0 +1,43 @@
+.TH MKDIR 1
+.SH NAME
+mkdir \- make a directory
+.SH SYNOPSIS
+.B mkdir
+[
+.B -p
+] [
+.B -m
+. I mode
+]
+.I dirname ...
+.SH DESCRIPTION
+.I Mkdir
+creates the specified directories.
+It
+requires write permission in the parent directory.
+.PP
+If the
+.B -p
+flag is given,
+.I mkdir
+creates any necessary parent directories
+and does not complain if the target directory already exists.
+.PP
+The
+.B -m
+flag sets the permissions to be used when creating the directory.
+The default is 0777.
+.SH "SEE ALSO"
+.IR rm (1)
+.br
+.IR cd
+in
+.IR rc (1)
+.SH SOURCE
+.B \*9/src/cmd/mkdir.c
+.SH DIAGNOSTICS
+.I Mkdir
+returns null exit status if all directories were successfully made.
+Otherwise it prints a diagnostic and returns
+.B \&"error"
+status.
diff --git a/tac/Makefile b/tac/Makefile
@@ -1,10 +0,0 @@
-# tac - reverse line order cat
-# Depends on ../lib9
-
-TARG = tac
-
-include ../std.mk
-
-pre-uninstall:
-
-post-install:
diff --git a/tac/tac.1 b/tac/tac.1
@@ -1,28 +0,0 @@
-.TH TAC 1
-.SH NAME
-tac \- reverse concatenate files
-.SH SYNOPSIS
-.B tac
-[
-.I file ...
-]
-.SH DESCRIPTION
-.I Tac
-reads each
-.I file
-in sequence and writes it on the standard output in reverse line order.
-.IP
-.L
-tac file
-.LP
-prints a file in reverse line order
-.IP
-.L
-tac file1 file2 >file3
-.LP
-Concatenate reversed file1 and file2 into file3
-.LP
-.SH SEE ALSO
-.IR cat (1)
-.SH BUGS
-Same as in cat
diff --git a/tac/tac.c b/tac/tac.c
@@ -1,60 +0,0 @@
-/* author: pancake<nopcode.org> */
-#include <u.h>
-#include <libc.h>
-
-static vlong bsize = 0;
-static char *buf;
-#define LINES 4096
-
-void
-tac()
-{
- int i, j;
- char *ptr, **nls;
- nls = malloc(LINES*sizeof(nls));
- for(i=1, ptr=buf; ptr;) {
- assert(nls != NULL);
- for(j=0; j<LINES && (ptr=strchr(ptr+1, '\n')); j++)
- nls[i++] = ptr+1;
- nls = realloc(nls, (i+LINES)*sizeof(nls));
- }
- *nls = buf;
- while(i--)
- write(1, nls[i], nls[i+1]-nls[i]);
- free(nls);
-}
-
-void
-load(int f)
-{
- vlong nsize, size = seek(f, 0, 2);
- if (size>0) {
- nsize = bsize + size;
- buf = realloc(buf, nsize);
- seek(f, 0, 0);
- read(f, buf+bsize, size);
- bsize = nsize;
- } else
- while ((size = read(f, buf+bsize, LINES))>0)
- bsize+=size;
-}
-
-void
-main(int argc, char *argv[])
-{
- int i, f;
- buf = malloc(1);
- assert(buf != NULL);
- if (argc == 1)
- load(0);
- else for(i=1; i<argc; i++){
- f = open(argv[i], OREAD);
- if(f >= 0){
- load(f);
- close(f);
- }else sysfatal("can't open %s: %r", argv[i]);
- }
- tac();
- free(buf);
- exits(0);
-}
diff --git a/tail/Makefile b/tail/Makefile
@@ -0,0 +1,11 @@
+# tail - tail unix port from plan9
+#
+# Depends on ../lib9
+
+TARG = tail
+
+include ../std.mk
+
+pre-uninstall:
+
+post-install:
diff --git a/tail/tail.1 b/tail/tail.1
@@ -0,0 +1,87 @@
+.TH TAIL 1
+.SH NAME
+tail \- deliver the last part of a file
+.SH SYNOPSIS
+.B tail
+[
+.BR +- \fInumber\fP[ lbc ][ rf ]
+]
+[
+.I file
+]
+.PP
+.B tail
+[
+.B -fr
+]
+[
+.B -n
+.I nlines
+]
+[
+.B -c
+.I nbytes
+]
+[
+.I file
+]
+.SH DESCRIPTION
+.I Tail
+copies the named file to the standard output beginning
+at a designated place.
+If no file is named, the standard input is copied.
+.PP
+Copying begins at position
+.BI + number
+measured from the beginning, or
+.BI - number
+from the end of the input.
+.I Number
+is counted in lines, 1K blocks or bytes,
+according to the appended flag
+.LR l ,
+.LR b ,
+or
+.LR c .
+Default is
+.B -10l
+(ten ell).
+.PP
+The further flag
+.L r
+causes tail to print lines from the end of the file in reverse order;
+.L f
+(follow) causes
+.IR tail ,
+after printing to the end, to keep watch and
+print further data as it appears.
+.PP
+The second syntax is that promulgated by POSIX, where
+the
+.I numbers
+rather than the options are signed.
+.SH EXAMPLES
+.TP
+.B tail file
+Print the last 10 lines of a file.
+.TP
+.B tail +0f file
+Print a file, and continue to watch
+data accumulate as it grows.
+.TP
+.B sed 10q file
+Print the first 10 lines of a file.
+.SH SOURCE
+.B \*9/src/cmd/tail.c
+.SH BUGS
+Tails relative to the end of the file
+are treasured up in a buffer, and thus
+are limited in length.
+.PP
+According to custom, option
+.BI + number
+counts lines from 1, and counts
+blocks and bytes from 0.
+.PP
+.I Tail
+is ignorant of UTF.
diff --git a/tail/tail.c b/tail/tail.c
@@ -0,0 +1,363 @@
+#include <u.h>
+#include <libc.h>
+#include <ctype.h>
+#include <bio.h>
+
+/*
+ * tail command, posix plus v10 option -r.
+ * the simple command tail -c, legal in v10, is illegal
+ */
+
+vlong count;
+int anycount;
+int follow;
+int file = 0;
+char* umsg = "usage: tail [-n N] [-c N] [-f] [-r] [+-N[bc][fr]] …
+
+Biobuf bout;
+enum
+{
+ BEG,
+ END
+} origin = END;
+enum
+{
+ CHARS,
+ LINES
+} units = LINES;
+enum
+{
+ FWD,
+ REV
+} dir = FWD;
+
+extern void copy(void);
+extern void fatal(char*);
+extern int getnumber(char*);
+extern void keep(void);
+extern void reverse(void);
+extern void skip(void);
+extern void suffix(char*);
+extern long tread(char*, long);
+#define trunc tailtrunc
+extern void trunc(Dir*, Dir**);
+extern vlong tseek(vlong, int);
+extern void twrite(char*, long);
+extern void usage(void);
+
+#define JUMP(o,p) tseek(o,p), copy()
+
+void
+main(int argc, char **argv)
+{
+ int seekable, c;
+
+ Binit(&bout, 1, OWRITE);
+ for(; argc > 1 && ((c=*argv[1])=='-'||c=='+'); argc--,argv++ ) {
+ if(getnumber(argv[1])) {
+ suffix(argv[1]);
+ continue;
+ } else
+ if(c == '-')
+ switch(argv[1][1]) {
+ case 'c':
+ units = CHARS;
+ case 'n':
+ if(getnumber(argv[1]+2))
+ continue;
+ else
+ if(argc > 2 && getnumber(argv[2])) {
+ argc--, argv++;
+ continue;
+ } else
+ usage();
+ case 'r':
+ dir = REV;
+ continue;
+ case 'f':
+ follow++;
+ continue;
+ case '-':
+ argc--, argv++;
+ }
+ break;
+ }
+ if(dir==REV && (units==CHARS || follow || origin==BEG))
+ fatal("incompatible options");
+ if(!anycount)
+ count = dir==REV? ~0ULL>>1: 10;
+ if(origin==BEG && units==LINES && count>0)
+ count--;
+ if(argc > 2)
+ usage();
+ if(argc > 1 && (file=open(argv[1],0)) < 0)
+ fatal(argv[1]);
+ seekable = seek(file,0L,0) == 0;
+
+ if(!seekable && origin==END)
+ keep();
+ else
+ if(!seekable && origin==BEG)
+ skip();
+ else
+ if(units==CHARS && origin==END)
+ JUMP(-count, 2);
+ else
+ if(units==CHARS && origin==BEG)
+ JUMP(count, 0);
+ else
+ if(units==LINES && origin==END)
+ reverse();
+ else
+ if(units==LINES && origin==BEG)
+ skip();
+ if(follow && seekable)
+ for(;;) {
+ static Dir *sb0, *sb1;
+ trunc(sb1, &sb0);
+ copy();
+ trunc(sb0, &sb1);
+ sleep(5000);
+ }
+ exits(0);
+}
+
+void
+trunc(Dir *old, Dir **new)
+{
+ Dir *d;
+ vlong olength;
+
+ d = dirfstat(file);
+ if(d == nil)
+ return;
+ olength = 0;
+ if(old)
+ olength = old->length;
+ if(d->length < olength)
+ d->length = tseek(0L, 0);
+ free(*new);
+ *new = d;
+}
+
+void
+suffix(char *s)
+{
+ while(*s && strchr("0123456789+-", *s))
+ s++;
+ switch(*s) {
+ case 'b':
+ if((count *= 1024) < 0)
+ fatal("too big");
+ case 'c':
+ units = CHARS;
+ case 'l':
+ s++;
+ }
+ switch(*s) {
+ case 'r':
+ dir = REV;
+ return;
+ case 'f':
+ follow++;
+ return;
+ case 0:
+ return;
+ }
+ usage();
+}
+
+/*
+ * read past head of the file to find tail
+ */
+void
+skip(void)
+{
+ int i;
+ long n;
+ char buf[Bsize];
+ if(units == CHARS) {
+ for( ; count>0; count -=n) {
+ n = count<Bsize? count: Bsize;
+ if(!(n = tread(buf, n)))
+ return;
+ }
+ } else /*units == LINES*/ {
+ n = i = 0;
+ while(count > 0) {
+ if(!(n = tread(buf, Bsize)))
+ return;
+ for(i=0; i<n && count>0; i++)
+ if(buf[i]=='\n')
+ count--;
+ }
+ twrite(buf+i, n-i);
+ }
+ copy();
+}
+
+void
+copy(void)
+{
+ long n;
+ char buf[Bsize];
+ while((n=tread(buf, Bsize)) > 0) {
+ twrite(buf, n);
+ Bflush(&bout); /* for FWD on pipe; else harmless */
+ }
+}
+
+/*
+ * read whole file, keeping the tail
+ * complexity is length(file)*length(tail).
+ * could be linear.
+ */
+void
+keep(void)
+{
+ int len = 0;
+ long bufsiz = 0;
+ char *buf = 0;
+ int j, k, n;
+
+ for(n=1; n;) {
+ if(len+Bsize > bufsiz) {
+ bufsiz += 2*Bsize;
+ if(!(buf = realloc(buf, bufsiz+1)))
+ fatal("out of space");
+ }
+ for(; n && len<bufsiz; len+=n)
+ n = tread(buf+len, bufsiz-len);
+ if(count >= len)
+ continue;
+ if(units == CHARS)
+ j = len - count;
+ else {
+ /* units == LINES */
+ j = buf[len-1]=='\n'? len-1: len;
+ for(k=0; j>0; j--)
+ if(buf[j-1] == '\n')
+ if(++k >= count)
+ break;
+ }
+ memmove(buf, buf+j, len-=j);
+ }
+ if(dir == REV) {
+ if(len>0 && buf[len-1]!='\n')
+ buf[len++] = '\n';
+ for(j=len-1 ; j>0; j--)
+ if(buf[j-1] == '\n') {
+ twrite(buf+j, len-j);
+ if(--count <= 0)
+ return;
+ len = j;
+ }
+ }
+ if(count > 0)
+ twrite(buf, len);
+}
+
+/*
+ * count backward and print tail of file
+ */
+void
+reverse(void)
+{
+ int first;
+ long len = 0;
+ long n = 0;
+ long bufsiz = 0;
+ char *buf = 0;
+ vlong pos = tseek(0L, 2);
+
+ for(first=1; pos>0 && count>0; first=0) {
+ n = pos>Bsize? Bsize: (int)pos;
+ pos -= n;
+ if(len+n > bufsiz) {
+ bufsiz += 2*Bsize;
+ if(!(buf = realloc(buf, bufsiz+1)))
+ fatal("out of space");
+ }
+ memmove(buf+n, buf, len);
+ len += n;
+ tseek(pos, 0);
+ if(tread(buf, n) != n)
+ fatal("length error");
+ if(first && buf[len-1]!='\n')
+ buf[len++] = '\n';
+ for(n=len-1 ; n>0 && count>0; n--)
+ if(buf[n-1] == '\n') {
+ count--;
+ if(dir == REV)
+ twrite(buf+n, len-n);
+ len = n;
+ }
+ }
+ if(dir == FWD) {
+ tseek(n==0? 0 : pos+n+1, 0);
+ copy();
+ } else
+ if(count > 0)
+ twrite(buf, len);
+}
+
+vlong
+tseek(vlong o, int p)
+{
+ o = seek(file, o, p);
+ if(o == -1)
+ fatal("");
+ return o;
+}
+
+long
+tread(char *buf, long n)
+{
+ int r = read(file, buf, n);
+ if(r == -1)
+ fatal("");
+ return r;
+}
+
+void
+twrite(char *s, long n)
+{
+ if(Bwrite(&bout, s, n) != n)
+ fatal("");
+}
+
+int
+getnumber(char *s)
+{
+ if(*s=='-' || *s=='+')
+ s++;
+ if(!isdigit((uchar)*s))
+ return 0;
+ if(s[-1] == '+')
+ origin = BEG;
+ if(anycount++)
+ fatal("excess option");
+ count = atol(s);
+
+ /* check range of count */
+ if(count < 0 || (int)count != count)
+ fatal("too big");
+ return 1;
+}
+
+void
+fatal(char *s)
+{
+ char buf[ERRMAX];
+
+ errstr(buf, sizeof buf);
+ fprint(2, "tail: %s: %s\n", s, buf);
+ exits(s);
+}
+
+void
+usage(void)
+{
+ fprint(2, "%s\n", umsg);
+ exits("usage");
+}
You are viewing proxied material from suckless.org. The copyright of proxied material belongs to its original authors. Any comments or complaints in relation to proxied material should be directed to the original authors of the content concerned. Please see the disclaimer for more details.