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 delimlen) 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, "<stdout>"); 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], stdout, "<stdout>"); 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_rune))) { 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 }