fold.c - sbase - suckless unix tools
 (HTM) git clone git://git.suckless.org/sbase
 (DIR) Log
 (DIR) Files
 (DIR) Refs
 (DIR) README
 (DIR) 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 }