sbase

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

expand.c (2300B)


      1 /* See LICENSE file for copyright and license details. */
      2 #include <stdint.h>
      3 #include <stdlib.h>
      4 #include <string.h>
      5 
      6 #include "utf.h"
      7 #include "util.h"
      8 
      9 static int     iflag      = 0;
     10 static size_t *tablist    = NULL;
     11 static size_t  tablistlen = 0;
     12 
     13 static size_t
     14 parselist(const char *s)
     15 {
     16 	size_t i;
     17 	char  *p, *tmp;
     18 
     19 	tmp = estrdup(s);
     20 	for (i = 0; (p = strsep(&tmp, " ,")); i++) {
     21 		if (*p == '\0')
     22 			eprintf("empty field in tablist\n");
     23 		tablist = ereallocarray(tablist, i + 1, sizeof(*tablist));
     24 		tablist[i] = estrtonum(p, 1, MIN(LLONG_MAX, SIZE_MAX));
     25 		if (i > 0 && tablist[i - 1] >= tablist[i])
     26 			eprintf("tablist must be ascending\n");
     27 	}
     28 	tablist = ereallocarray(tablist, i + 1, sizeof(*tablist));
     29 	/* tab length = 1 for the overflowing case later in the matcher */
     30 	tablist[i] = 1;
     31 
     32 	return i;
     33 }
     34 
     35 static int
     36 expand(const char *file, FILE *fp)
     37 {
     38 	size_t bol = 1, col = 0, i;
     39 	Rune r;
     40 
     41 	while (efgetrune(&r, fp, file)) {
     42 		switch (r) {
     43 		case '\t':
     44 			if (tablistlen == 1)
     45 				i = 0;
     46 			else for (i = 0; i < tablistlen; i++)
     47 				if (col < tablist[i])
     48 					break;
     49 			if (bol || !iflag) {
     50 				do {
     51 					col++;
     52 					putchar(' ');
     53 				} while (col % tablist[i]);
     54 			} else {
     55 				putchar('\t');
     56 				col = tablist[i];
     57 			}
     58 			break;
     59 		case '\b':
     60 			bol = 0;
     61 			if (col)
     62 				col--;
     63 			putchar('\b');
     64 			break;
     65 		case '\n':
     66 			bol = 1;
     67 			col = 0;
     68 			putchar('\n');
     69 			break;
     70 		default:
     71 			col++;
     72 			if (r != ' ')
     73 				bol = 0;
     74 			efputrune(&r, stdout, "<stdout>");
     75 			break;
     76 		}
     77 	}
     78 
     79 	return 0;
     80 }
     81 
     82 static void
     83 usage(void)
     84 {
     85 	eprintf("usage: %s [-i] [-t tablist] [file ...]\n", argv0);
     86 }
     87 
     88 int
     89 main(int argc, char *argv[])
     90 {
     91 	FILE *fp;
     92 	int ret = 0;
     93 	char *tl = "8";
     94 
     95 	ARGBEGIN {
     96 	case 'i':
     97 		iflag = 1;
     98 		break;
     99 	case 't':
    100 		tl = EARGF(usage());
    101 		if (!*tl)
    102 			eprintf("tablist cannot be empty\n");
    103 		break;
    104 	default:
    105 		usage();
    106 	} ARGEND
    107 
    108 	tablistlen = parselist(tl);
    109 
    110 	if (!argc) {
    111 		expand("<stdin>", stdin);
    112 	} else {
    113 		for (; *argv; argc--, argv++) {
    114 			if (!strcmp(*argv, "-")) {
    115 				*argv = "<stdin>";
    116 				fp = stdin;
    117 			} else if (!(fp = fopen(*argv, "r"))) {
    118 				weprintf("fopen %s:", *argv);
    119 				ret = 1;
    120 				continue;
    121 			}
    122 			expand(*argv, fp);
    123 			if (fp != stdin && fshut(fp, *argv))
    124 				ret = 1;
    125 		}
    126 	}
    127 
    128 	ret |= fshut(stdin, "<stdin>") | fshut(stdout, "<stdout>");
    129 
    130 	return ret;
    131 }