Index: rev.1 =================================================================== --- rev.1 (wersja 179650) +++ rev.1 (kopia robocza) @@ -32,7 +32,7 @@ .\" @(#)rev.1 8.1 (Berkeley) 6/9/93 .\" $FreeBSD$ .\" -.Dd June 9, 1993 +.Dd July 8, 2008 .Dt REV 1 .Os .Sh NAME @@ -41,9 +41,19 @@ .Sh SYNOPSIS .Nm .Op Ar +.Nm +.Fl l +.Ar file ... .Sh DESCRIPTION The .Nm utility copies the specified files to the standard output, reversing the order of characters in every line. If no files are specified, the standard input is read. +.Pp +Flag +.Fl l +can be used in order to reverse order of lines present in a file. Note +that +.Ar file +must be specified. Index: Makefile =================================================================== --- Makefile (wersja 179650) +++ Makefile (kopia robocza) @@ -3,4 +3,6 @@ PROG= rev +WARNS+= 7 + .include Index: rev.c =================================================================== --- rev.c (wersja 179650) +++ rev.c (kopia robocza) @@ -47,6 +47,8 @@ __FBSDID("$FreeBSD$"); #include +#include +#include #include #include @@ -56,22 +58,26 @@ #include #include #include +#include void usage(void); - +static int reverse_chars(char **argv); +static int reverse_lines(char **argv); + int main(int argc, char *argv[]) { - const char *filename; - wchar_t *p, *t; - FILE *fp; - size_t len; - int ch, rval; + int ch, flag_l, rval; + ch = flag_l = rval = 0; + setlocale(LC_ALL, ""); - while ((ch = getopt(argc, argv, "")) != -1) + while ((ch = getopt(argc, argv, "l")) != -1) switch(ch) { + case 'l': + flag_l++; + break; case '?': default: usage(); @@ -80,9 +86,33 @@ argc -= optind; argv += optind; + if (flag_l) + rval = reverse_lines(argv); + else + rval = reverse_chars(argv); + exit(rval); +} + +void +usage(void) +{ + (void)fprintf(stderr, "usage: rev [-l file ... | [file ...]]\n"); + exit(1); +} + +static int +reverse_chars(char **argv) +{ + const char *filename; + wchar_t *p, *t; + FILE *fp; + size_t len; + int rval; + fp = stdin; filename = "stdin"; rval = 0; + do { if (*argv) { if ((fp = fopen(*argv, "r")) == NULL) { @@ -107,12 +137,71 @@ } (void)fclose(fp); } while(*argv); - exit(rval); + + return (rval); } -void -usage(void) +static int +reverse_lines(char **argv) { - (void)fprintf(stderr, "usage: rev [file ...]\n"); - exit(1); + char *av; + int fd, rval; + void *mem; + struct stat st; + char *e; + char *b; + + av = NULL; + fd = rval = 0; + + for (;;) { + av = *argv++; + if (av == NULL) + break; + fd = open(av, O_RDONLY); + if (fd == -1) { + warn("Couldn't open file %s", av); + break; + } + rval = fstat(fd, &st); + if (rval == -1) { + warn("Couldn't fstat() file %s", av); + break; + } + mem = mmap(NULL, st.st_size, PROT_READ, MAP_SHARED, fd, 0); + if (mem == MAP_FAILED) { + warn("Wasn't able to mmap() memory"); + break; + } + + /* End of the last line */ + e = ((char *)mem + st.st_size); + if (*e == '\0') + e--; + if (*e == '\n') + e--; + b = e; + + /* + * Go from the last character present in the memory to + * the first one which is not '\n'. Take which portion + * and write it to the standard output. + */ + for (b = e; b >= (char *)mem; ) { + if (*b == '\0') + break; + while (*b != '\n' && *b != '\0') + b--; + write(1, b + 1, e - b + 1); + e = b - 1; + b = e; + } + close(fd); + rval = munmap(mem, st.st_size); + if (rval != 0) { + warn("Couldn't unmap memory with munmap()"); + break; + } + } + return (rval); }