Add c-flag to tail(1) and refactor manpage
and mark it as finished in README.
This commit is contained in:
		
							
								
								
									
										2
									
								
								README
									
									
									
									
									
								
							
							
						
						
									
										2
									
								
								README
									
									
									
									
									
								
							| @@ -64,7 +64,7 @@ The following tools are implemented ('*' == finished, '#' == UTF-8 support, | |||||||
| =* sponge          non-posix                    none | =* sponge          non-posix                    none | ||||||
|    strings         no                           -a, -n, -t |    strings         no                           -a, -n, -t | ||||||
| =* sync            non-posix                    none | =* sync            non-posix                    none | ||||||
| =  tail            no                           -c | =* tail            yes                          none | ||||||
| =* tar             non-posix                    none | =* tar             non-posix                    none | ||||||
| =* tee             yes                          none | =* tee             yes                          none | ||||||
|    test            yes                          none |    test            yes                          none | ||||||
|   | |||||||
							
								
								
									
										25
									
								
								tail.1
									
									
									
									
									
								
							
							
						
						
									
										25
									
								
								tail.1
									
									
									
									
									
								
							| @@ -7,7 +7,7 @@ | |||||||
| .Sh SYNOPSIS | .Sh SYNOPSIS | ||||||
| .Nm | .Nm | ||||||
| .Op Fl f | .Op Fl f | ||||||
| .Op Fl n Ar num | .Op Fl c Ar num | Fl n Ar num | ||||||
| .Op Ar file ... | .Op Ar file ... | ||||||
| .Sh DESCRIPTION | .Sh DESCRIPTION | ||||||
| .Nm | .Nm | ||||||
| @@ -20,19 +20,28 @@ is given, | |||||||
| reads from stdin. | reads from stdin. | ||||||
| .Sh OPTIONS | .Sh OPTIONS | ||||||
| .Bl -tag -width Ds | .Bl -tag -width Ds | ||||||
|  | .It Fl c Ar num | Fl n Ar num | ||||||
|  | Display | ||||||
|  | .Ar num | ||||||
|  | last characters | lines. If | ||||||
|  | .Ar num | ||||||
|  | begins with '+' it is used as an offset from the beginning of each | ||||||
|  | .Ar file . | ||||||
|  | If | ||||||
|  | .Ar num | ||||||
|  | begins with '-' it is handled the same as if no sign was given. | ||||||
| .It Fl f | .It Fl f | ||||||
| If one | If one | ||||||
| .Ar file | .Ar file | ||||||
| is specified, append lines to output as | is specified, append lines to output as | ||||||
| .Ar file | .Ar file | ||||||
| grows. | grows. | ||||||
| .It Fl n Ar lines |  | ||||||
| Display |  | ||||||
| .Ar num |  | ||||||
| lines. If |  | ||||||
| .Ar num |  | ||||||
| begins with '+' it is used as an offset from the beginning of each |  | ||||||
| .Ar file . |  | ||||||
| .El | .El | ||||||
| .Sh SEE ALSO | .Sh SEE ALSO | ||||||
| .Xr head 1 | .Xr head 1 | ||||||
|  | .Sh STANDARDS | ||||||
|  | The | ||||||
|  | .Nm | ||||||
|  | utility is compliant with the | ||||||
|  | .St -p1003.1-2008 | ||||||
|  | specification. | ||||||
|   | |||||||
							
								
								
									
										44
									
								
								tail.c
									
									
									
									
									
								
							
							
						
						
									
										44
									
								
								tail.c
									
									
									
									
									
								
							| @@ -9,43 +9,61 @@ | |||||||
| #include <unistd.h> | #include <unistd.h> | ||||||
|  |  | ||||||
| #include "text.h" | #include "text.h" | ||||||
|  | #include "utf.h" | ||||||
| #include "util.h" | #include "util.h" | ||||||
|  |  | ||||||
| static int fflag = 0; | static int fflag = 0; | ||||||
|  |  | ||||||
| static void | static void | ||||||
| dropinit(FILE *fp, const char *str, size_t n) | dropinit(FILE *fp, const char *str, size_t n, char mode) | ||||||
| { | { | ||||||
|  | 	Rune r; | ||||||
| 	char *buf = NULL; | 	char *buf = NULL; | ||||||
| 	size_t size = 0, i = 0; | 	size_t size = 0, i = 0; | ||||||
| 	ssize_t len; | 	ssize_t len; | ||||||
|  |  | ||||||
|  | 	if (mode == 'n') { | ||||||
| 		while (i < n && (len = getline(&buf, &size, fp)) != -1) | 		while (i < n && (len = getline(&buf, &size, fp)) != -1) | ||||||
| 			if (len > 0 && buf[len - 1] == '\n') | 			if (len > 0 && buf[len - 1] == '\n') | ||||||
| 				i++; | 				i++; | ||||||
|  | 	} else { | ||||||
|  | 		while (i < n && (len = readrune(str, fp, &r))) | ||||||
|  | 			i++; | ||||||
|  | 	} | ||||||
| 	free(buf); | 	free(buf); | ||||||
| 	concat(fp, str, stdout, "<stdout>"); | 	concat(fp, str, stdout, "<stdout>"); | ||||||
| } | } | ||||||
|  |  | ||||||
| static void | static void | ||||||
| taketail(FILE *fp, const char *str, size_t n) | taketail(FILE *fp, const char *str, size_t n, char mode) | ||||||
| { | { | ||||||
|  | 	Rune *r = NULL; | ||||||
| 	char **ring = NULL; | 	char **ring = NULL; | ||||||
| 	size_t i, j, *size = NULL; | 	size_t i, j, *size = NULL; | ||||||
|  |  | ||||||
|  | 	if (mode == 'n') { | ||||||
| 		ring = ecalloc(n, sizeof *ring); | 		ring = ecalloc(n, sizeof *ring); | ||||||
| 		size = ecalloc(n, sizeof *size); | 		size = ecalloc(n, sizeof *size); | ||||||
|  |  | ||||||
| 		for (i = j = 0; getline(&ring[i], &size[i], fp) != -1; ) | 		for (i = j = 0; getline(&ring[i], &size[i], fp) != -1; ) | ||||||
| 			i = j = (i + 1) % n; | 			i = j = (i + 1) % n; | ||||||
|  | 	} else { | ||||||
|  | 		r = ecalloc(n, sizeof *r); | ||||||
|  |  | ||||||
|  | 		for (i = j = 0; readrune(str, fp, &r[i]); ) | ||||||
|  | 			i = j = (i + 1) % n; | ||||||
|  | 	} | ||||||
| 	if (ferror(fp)) | 	if (ferror(fp)) | ||||||
| 		eprintf("%s: read error:", str); | 		eprintf("%s: read error:", str); | ||||||
|  |  | ||||||
| 	do { | 	do { | ||||||
| 		if (ring[j]) { | 		if (ring && ring[j]) { | ||||||
| 			fputs(ring[j], stdout); | 			fputs(ring[j], stdout); | ||||||
| 			free(ring[j]); | 			free(ring[j]); | ||||||
| 		} | 		} | ||||||
|  | 		if (r) { | ||||||
|  | 			writerune("<stdout>", stdout, &r[j]); | ||||||
|  | 		} | ||||||
| 	} while ((j = (j + 1) % n) != i); | 	} while ((j = (j + 1) % n) != i); | ||||||
|  |  | ||||||
| 	free(ring); | 	free(ring); | ||||||
| @@ -63,30 +81,32 @@ main(int argc, char *argv[]) | |||||||
| { | { | ||||||
| 	struct stat st1, st2; | 	struct stat st1, st2; | ||||||
| 	FILE *fp; | 	FILE *fp; | ||||||
| 	size_t n = 10, tmpsize; | 	size_t num = 10, tmpsize; | ||||||
| 	int ret = 0, newline, many; | 	int ret = 0, newline, many; | ||||||
| 	char *lines, *tmp; | 	char mode = 'n', *numstr, *tmp; | ||||||
| 	void (*tail)(FILE *, const char *, size_t) = taketail; | 	void (*tail)(FILE *, const char *, size_t, char) = taketail; | ||||||
|  |  | ||||||
| 	ARGBEGIN { | 	ARGBEGIN { | ||||||
| 	case 'f': | 	case 'f': | ||||||
| 		fflag = 1; | 		fflag = 1; | ||||||
| 		break; | 		break; | ||||||
|  | 	case 'c': | ||||||
| 	case 'n': | 	case 'n': | ||||||
| 		lines = EARGF(usage()); | 		mode = ARGC(); | ||||||
| 		n = MIN(llabs(estrtonum(lines, LLONG_MIN + 1, MIN(LLONG_MAX, SIZE_MAX))), SIZE_MAX); | 		numstr = EARGF(usage()); | ||||||
| 		if (strchr(lines, '+')) | 		num = MIN(llabs(estrtonum(numstr, LLONG_MIN + 1, MIN(LLONG_MAX, SIZE_MAX))), SIZE_MAX); | ||||||
|  | 		if (strchr(numstr, '+')) | ||||||
| 			tail = dropinit; | 			tail = dropinit; | ||||||
| 		break; | 		break; | ||||||
| 	ARGNUM: | 	ARGNUM: | ||||||
| 		n = ARGNUMF(); | 		num = ARGNUMF(); | ||||||
| 		break; | 		break; | ||||||
| 	default: | 	default: | ||||||
| 		usage(); | 		usage(); | ||||||
| 	} ARGEND; | 	} ARGEND; | ||||||
|  |  | ||||||
| 	if (argc == 0) | 	if (argc == 0) | ||||||
| 		tail(stdin, "<stdin>", n); | 		tail(stdin, "<stdin>", num, mode); | ||||||
| 	else { | 	else { | ||||||
| 		if ((many = argc > 1) && fflag) | 		if ((many = argc > 1) && fflag) | ||||||
| 			usage(); | 			usage(); | ||||||
| @@ -104,7 +124,7 @@ main(int argc, char *argv[]) | |||||||
| 			if (!(S_ISFIFO(st1.st_mode) || S_ISREG(st1.st_mode))) | 			if (!(S_ISFIFO(st1.st_mode) || S_ISREG(st1.st_mode))) | ||||||
| 				fflag = 0; | 				fflag = 0; | ||||||
| 			newline = 1; | 			newline = 1; | ||||||
| 			tail(fp, argv[0], n); | 			tail(fp, argv[0], num, mode); | ||||||
|  |  | ||||||
| 			if (fflag && argc == 1) { | 			if (fflag && argc == 1) { | ||||||
| 				tmp = NULL; | 				tmp = NULL; | ||||||
|   | |||||||
		Reference in New Issue
	
	Block a user