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 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 }