summaryrefslogtreecommitdiff
path: root/src/fold.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/fold.c')
-rw-r--r--src/fold.c123
1 files changed, 123 insertions, 0 deletions
diff --git a/src/fold.c b/src/fold.c
new file mode 100644
index 0000000..64e4534
--- /dev/null
+++ b/src/fold.c
@@ -0,0 +1,123 @@
+/*
+ * fold.c
+ * Implementation of SUSv3 XCU fold utility
+ * Copyright © 2007 Rich Felker
+ * Licensed under the terms of the GNU General Public License, v2 or later
+ */
+
+#include <stdlib.h>
+#include <stdint.h>
+#include <string.h>
+#include <stdio.h>
+#include <wchar.h>
+#include <wctype.h>
+#include <unistd.h>
+#include <limits.h>
+#include <locale.h>
+#include <errno.h>
+
+static void my_perror(char *prog, char *msg)
+{
+ char *err = strerror(errno);
+ write(2, prog, strlen(prog));
+ write(2, ": ", 2);
+ write(2, msg, strlen(msg));
+ write(2, ": ", 2);
+ write(2, err, strlen(err));
+ write(2, "\n", 1);
+}
+
+int main(int argc, char *argv[])
+{
+ int b;
+ char *name;
+ char dummy[MB_LEN_MAX];
+ size_t i, j, len=127;
+ wchar_t wc, *buf = malloc(sizeof wc * len);
+ long col, out_col, width=80;
+ int w;
+ int splitable;
+ int byte=0, space=0;
+ FILE *f;
+
+ if (!setlocale(LC_CTYPE, ""))
+ my_perror(argv[0], "setlocale");
+
+ while ((b = getopt(argc, argv, "bsw:")) != EOF) switch(b) {
+ case 'b': byte=1; break;
+ case 's': space=1; break;
+ case 'w':
+ width=strtoul(optarg, NULL, 10);
+ break;
+ default:
+ return 1;
+ }
+
+ if (optind == argc) {
+ f = stdin;
+ name = "-";
+ goto nofiles;
+ }
+
+ while (optind < argc) {
+ f = fopen(name=argv[optind++], "rb");
+ if (!f) {
+ my_perror(argv[0], name);
+ continue;
+ }
+nofiles:
+ i = col = out_col = 0;
+ splitable = -1;
+ while ((wc = getwc(f))>=0) {
+ if (i == len) {
+ buf = realloc(buf, sizeof wc * (len=len<<1|1));
+ if (!buf) {
+ my_perror(argv[0], "realloc");
+ return 1;
+ }
+ }
+ buf[i++] = wc;
+
+ if (wc == '\n') {
+ col = 0;
+ splitable = -1;
+ goto output;
+ }
+ else if (byte) w = wctomb(dummy, wc);
+ else if (wc == '\t') {
+ w = 8-(col&7);
+ if (w > width - col) w = 8;
+ }
+ else if (wc == '\r') col = w = 0;
+ else if (wc == '\b') {
+ if (col) col--;
+ w = 0;
+ }
+ else w = wcwidth(wc);
+
+ if (col && w > width - col) {
+ if (putwchar('\n')==WEOF) goto werr;
+ col -= out_col;
+ splitable = -1;
+ }
+ col += w;
+
+ if (space && iswblank(wc))
+ splitable = 1;
+ if (splitable) {
+output:
+ for (j=0; j<i; j++)
+ if (putwchar(buf[j])==WEOF) goto werr;
+ i = 0;
+ out_col = col;
+ splitable >>= 1;
+ }
+ }
+ if (ferror(f)) my_perror(argv[0], name);
+ if (f != stdin) fclose(f);
+ }
+ return 0;
+werr:
+ my_perror(argv[0], "write error");
+ return 1;
+}