Just like with head(1), rev(1)'s main loop is obfuscated.
This patch moves the open/read/write/close portion of the main loop
out of main() into a separate function, rev_file(). "multibyte"
becomes a global.
I think the result is easier to understand at a glance.
In a subsequent patch I want to drop the "rpath" promise in the
no-file branch, but that needs to wait.
ok?
Index: rev.c
===================================================================
RCS file: /cvs/src/usr.bin/rev/rev.c,v
retrieving revision 1.14
diff -u -p -r1.14 rev.c
--- rev.c 13 Jan 2022 05:10:46 -0000 1.14
+++ rev.c 27 Jan 2022 14:50:41 -0000
@@ -40,17 +40,16 @@
#include <string.h>
#include <unistd.h>
+int multibyte;
+
int isu8cont(unsigned char);
+int rev_file(const char *);
void usage(void);
int
main(int argc, char *argv[])
{
- char *filename, *p = NULL, *t, *te, *u;
- FILE *fp;
- ssize_t len;
- size_t ps = 0;
- int ch, multibyte, rval;
+ int ch, rval;
setlocale(LC_CTYPE, "");
multibyte = MB_CUR_MAX > 1;
@@ -67,40 +66,13 @@ main(int argc, char *argv[])
argc -= optind;
argv += optind;
- fp = stdin;
- filename = "stdin";
rval = 0;
- do {
- if (*argv) {
- if ((fp = fopen(*argv, "r")) == NULL) {
- warn("%s", *argv);
- rval = 1;
- ++argv;
- continue;
- }
- filename = *argv++;
- }
- while ((len = getline(&p, &ps, fp)) != -1) {
- if (p[len - 1] == '\n')
- --len;
- for (t = p + len - 1; t >= p; --t) {
- te = t;
- if (multibyte)
- while (t > p && isu8cont(*t))
- --t;
- for (u = t; u <= te; ++u)
- if (putchar(*u) == EOF)
- err(1, "stdout");
- }
- if (putchar('\n') == EOF)
- err(1, "stdout");
- }
- if (ferror(fp)) {
- warn("%s", filename);
- rval = 1;
- }
- (void)fclose(fp);
- } while(*argv);
+ if (argc == 0) {
+ rval = rev_file(NULL);
+ } else {
+ for (; *argv != NULL; argv++)
+ rval |= rev_file(*argv);
+ }
return rval;
}
@@ -108,6 +80,54 @@ int
isu8cont(unsigned char c)
{
return (c & (0x80 | 0x40)) == 0x80;
+}
+
+int
+rev_file(const char *path)
+{
+ char *p = NULL, *t, *te, *u;
+ const char *filename;
+ FILE *fp;
+ size_t ps = 0;
+ ssize_t len;
+ int rval = 0;
+
+ if (path != NULL) {
+ fp = fopen(path, "r");
+ if (fp == NULL) {
+ warn("%s", path);
+ return 1;
+ }
+ filename = path;
+ } else {
+ fp = stdin;
+ filename = "stdin";
+ }
+
+ while ((len = getline(&p, &ps, fp)) != -1) {
+ if (p[len - 1] == '\n')
+ --len;
+ for (t = p + len - 1; t >= p; --t) {
+ te = t;
+ if (multibyte)
+ while (t > p && isu8cont(*t))
+ --t;
+ for (u = t; u <= te; ++u)
+ if (putchar(*u) == EOF)
+ err(1, "stdout");
+ }
+ if (putchar('\n') == EOF)
+ err(1, "stdout");
+ }
+ free(p);
+ if (ferror(fp)) {
+ warn("%s", filename);
+ rval = 1;
+ }
+
+ (void)fclose(fp);
+
+ return rval;
}
void