sbase

suckless unix tools
git clone git://git.suckless.org/sbase
Log | Files | Refs | README | LICENSE

fold.c (2616B)


      1 /* See LICENSE file for copyright and license details. */
      2 #include <ctype.h>
      3 #include <stdint.h>
      4 #include <stdio.h>
      5 #include <stdlib.h>
      6 #include <string.h>
      7 
      8 #include "text.h"
      9 #include "util.h"
     10 #include "utf.h"
     11 
     12 static int    bflag = 0;
     13 static int    sflag = 0;
     14 static size_t width = 80;
     15 
     16 static void
     17 foldline(struct line *l, const char *fname) {
     18 	size_t i, col, last, spacesect, len;
     19 	Rune r;
     20 	int runelen;
     21 
     22 	for (i = 0, last = 0, col = 0, spacesect = 0; i < l->len; i += runelen) {
     23 		if (col >= width && ((l->data[i] != '\r' && l->data[i] != '\b') || bflag)) {
     24 			if (bflag && col > width)
     25 				i -= runelen;	/* never split a character */
     26 			len = ((sflag && spacesect) ? spacesect : i) - last;
     27 			if (fwrite(l->data + last, 1, len, stdout) != len)
     28 				eprintf("fwrite <stdout>:");
     29 			if (l->data[i] != '\n')
     30 				putchar('\n');
     31 			if (sflag && spacesect)
     32 				i = spacesect;
     33 			last = i;
     34 			col = 0;
     35 			spacesect = 0;
     36 		}
     37 		runelen = charntorune(&r, l->data + i, l->len - i);
     38 		if (!runelen || r == Runeerror)
     39 			eprintf("charntorune: %s: invalid utf\n", fname);
     40 		if (sflag && isblankrune(r))
     41 			spacesect = i + runelen;
     42 		if (!bflag && iscntrl(l->data[i])) {
     43 			switch(l->data[i]) {
     44 			case '\b':
     45 				col -= (col > 0);
     46 				break;
     47 			case '\r':
     48 				col = 0;
     49 				break;
     50 			case '\t':
     51 				col += (8 - (col % 8));
     52 				if (col >= width)
     53 					i--;
     54 				break;
     55 			}
     56 		} else {
     57 			col += bflag ? runelen : 1;
     58 		}
     59 	}
     60 	if (l->len - last)
     61 		fwrite(l->data + last, 1, l->len - last, stdout);
     62 }
     63 
     64 static void
     65 fold(FILE *fp, const char *fname)
     66 {
     67 	static struct line line;
     68 	static size_t size = 0;
     69 	ssize_t len;
     70 
     71 	while ((len = getline(&line.data, &size, fp)) > 0) {
     72 		line.len = len;
     73 		foldline(&line, fname);
     74 	}
     75 	if (ferror(fp))
     76 		eprintf("getline %s:", fname);
     77 }
     78 
     79 static void
     80 usage(void)
     81 {
     82 	eprintf("usage: %s [-bs] [-w num | -num] [FILE ...]\n", argv0);
     83 }
     84 
     85 int
     86 main(int argc, char *argv[])
     87 {
     88 	FILE *fp;
     89 	int ret = 0;
     90 
     91 	ARGBEGIN {
     92 	case 'b':
     93 		bflag = 1;
     94 		break;
     95 	case 's':
     96 		sflag = 1;
     97 		break;
     98 	case 'w':
     99 		width = estrtonum(EARGF(usage()), 1, MIN(LLONG_MAX, SIZE_MAX));
    100 		break;
    101 	ARGNUM:
    102 		if (!(width = ARGNUMF()))
    103 			eprintf("illegal width value, too small\n");
    104 		break;
    105 	default:
    106 		usage();
    107 	} ARGEND
    108 
    109 	if (!argc) {
    110 		fold(stdin, "<stdin>");
    111 	} else {
    112 		for (; *argv; argc--, argv++) {
    113 			if (!strcmp(*argv, "-")) {
    114 				*argv = "<stdin>";
    115 				fp = stdin;
    116 			} else if (!(fp = fopen(*argv, "r"))) {
    117 				weprintf("fopen %s:", *argv);
    118 				ret = 1;
    119 				continue;
    120 			}
    121 			fold(fp, *argv);
    122 			if (fp != stdin && fshut(fp, *argv))
    123 				ret = 1;
    124 		}
    125 	}
    126 
    127 	ret |= fshut(stdin, "<stdin>") | fshut(stdout, "<stdout>");
    128 
    129 	return ret;
    130 }