| paste.c - sbase - suckless unix tools | |
| git clone git://git.suckless.org/sbase | |
| Log | |
| Files | |
| Refs | |
| README | |
| LICENSE | |
| --- | |
| paste.c (2734B) | |
| --- | |
| 1 /* See LICENSE file for copyright and license details. */ | |
| 2 #include <stdlib.h> | |
| 3 #include <string.h> | |
| 4 | |
| 5 #include "utf.h" | |
| 6 #include "util.h" | |
| 7 | |
| 8 struct fdescr { | |
| 9 FILE *fp; | |
| 10 const char *name; | |
| 11 }; | |
| 12 | |
| 13 static void | |
| 14 sequential(struct fdescr *dsc, int fdescrlen, Rune *delim, size_t deliml… | |
| 15 { | |
| 16 Rune c, last; | |
| 17 size_t i, d; | |
| 18 | |
| 19 for (i = 0; i < fdescrlen; i++) { | |
| 20 d = 0; | |
| 21 last = 0; | |
| 22 | |
| 23 while (efgetrune(&c, dsc[i].fp, dsc[i].name)) { | |
| 24 if (last == '\n') { | |
| 25 if (delim[d] != '\0') | |
| 26 efputrune(&delim[d], stdout, "<s… | |
| 27 d = (d + 1) % delimlen; | |
| 28 } | |
| 29 | |
| 30 if (c != '\n') | |
| 31 efputrune(&c, stdout, "<stdout>"); | |
| 32 last = c; | |
| 33 } | |
| 34 | |
| 35 if (last == '\n') | |
| 36 efputrune(&last, stdout, "<stdout>"); | |
| 37 } | |
| 38 } | |
| 39 | |
| 40 static void | |
| 41 parallel(struct fdescr *dsc, int fdescrlen, Rune *delim, size_t delimlen) | |
| 42 { | |
| 43 Rune c, d; | |
| 44 size_t i, m; | |
| 45 ssize_t last; | |
| 46 | |
| 47 nextline: | |
| 48 last = -1; | |
| 49 | |
| 50 for (i = 0; i < fdescrlen; i++) { | |
| 51 d = delim[i % delimlen]; | |
| 52 c = 0; | |
| 53 | |
| 54 while (efgetrune(&c, dsc[i].fp, dsc[i].name)) { | |
| 55 for (m = last + 1; m < i; m++) { | |
| 56 if (delim[m % delimlen] != '\0') | |
| 57 efputrune(&delim[m % delimlen], … | |
| 58 } | |
| 59 last = i; | |
| 60 if (c == '\n') { | |
| 61 if (i != fdescrlen - 1) | |
| 62 c = d; | |
| 63 efputrune(&c, stdout, "<stdout>"); | |
| 64 break; | |
| 65 } | |
| 66 efputrune(&c, stdout, "<stdout>"); | |
| 67 } | |
| 68 | |
| 69 if (c == 0 && last != -1) { | |
| 70 if (i == fdescrlen - 1) | |
| 71 putchar('\n'); | |
| 72 else if (d != '\0') | |
| 73 efputrune(&d, stdout, "<stdout>"); | |
| 74 last++; | |
| 75 } | |
| 76 } | |
| 77 if (last != -1) | |
| 78 goto nextline; | |
| 79 } | |
| 80 | |
| 81 static void | |
| 82 usage(void) | |
| 83 { | |
| 84 eprintf("usage: %s [-s] [-d list] file ...\n", argv0); | |
| 85 } | |
| 86 | |
| 87 int | |
| 88 main(int argc, char *argv[]) | |
| 89 { | |
| 90 struct fdescr *dsc; | |
| 91 Rune *delim_rune = NULL; | |
| 92 size_t delim_runelen, i, delim_bytelen = 1; | |
| 93 int seq = 0, ret = 0; | |
| 94 char *delim = "\t"; | |
| 95 | |
| 96 ARGBEGIN { | |
| 97 case 's': | |
| 98 seq = 1; | |
| 99 break; | |
| 100 case 'd': | |
| 101 delim = EARGF(usage()); | |
| 102 delim_bytelen = unescape(delim); | |
| 103 break; | |
| 104 default: | |
| 105 usage(); | |
| 106 } ARGEND | |
| 107 | |
| 108 if (!argc) | |
| 109 usage(); | |
| 110 | |
| 111 /* populate delimiters */ | |
| 112 delim_rune = ereallocarray(NULL, | |
| 113 utfmemlen(delim, delim_bytelen) + 1, sizeof(*delim_rune)… | |
| 114 if (!(delim_runelen = utfntorunestr(delim, delim_bytelen, delim_… | |
| 115 usage(); | |
| 116 } | |
| 117 | |
| 118 /* populate file list */ | |
| 119 dsc = ereallocarray(NULL, argc, sizeof(*dsc)); | |
| 120 | |
| 121 for (i = 0; i < argc; i++) { | |
| 122 if (!strcmp(argv[i], "-")) { | |
| 123 argv[i] = "<stdin>"; | |
| 124 dsc[i].fp = stdin; | |
| 125 } else if (!(dsc[i].fp = fopen(argv[i], "r"))) { | |
| 126 eprintf("fopen %s:", argv[i]); | |
| 127 } | |
| 128 dsc[i].name = argv[i]; | |
| 129 } | |
| 130 | |
| 131 if (seq) { | |
| 132 sequential(dsc, argc, delim_rune, delim_runelen); | |
| 133 } else { | |
| 134 parallel(dsc, argc, delim_rune, delim_runelen); | |
| 135 } | |
| 136 | |
| 137 for (i = 0; i < argc; i++) | |
| 138 if (dsc[i].fp != stdin && fshut(dsc[i].fp, argv[i])) | |
| 139 ret |= fshut(dsc[i].fp, argv[i]); | |
| 140 | |
| 141 ret |= fshut(stdin, "<stdin>") | fshut(stdout, "<stdout>"); | |
| 142 | |
| 143 return ret; | |
| 144 } |