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