/*
* 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;
}