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 }