sbase

suckless unix tools
git clone git://git.2f30.org/sbase.git
Log | Files | Refs | README | LICENSE

paste.c (2590B)


      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 		for (; efgetrune(&c, dsc[i].fp, dsc[i].name) ;) {
     55 			for (m = last + 1; m < i; m++)
     56 				efputrune(&(delim[m % delimlen]), stdout, "<stdout>");
     57 			last = i;
     58 			if (c == '\n') {
     59 				if (i != fdescrlen - 1)
     60 					c = d;
     61 				efputrune(&c, stdout, "<stdout>");
     62 				break;
     63 			}
     64 			efputrune(&c, stdout, "<stdout>");
     65 		}
     66 
     67 		if (c == 0 && last != -1) {
     68 			if (i == fdescrlen - 1)
     69 				putchar('\n');
     70 			else
     71 				efputrune(&d, stdout, "<stdout>");
     72 			last++;
     73 		}
     74 	}
     75 	if (last != -1)
     76 		goto nextline;
     77 }
     78 
     79 static void
     80 usage(void)
     81 {
     82 	eprintf("usage: %s [-s] [-d list] file ...\n", argv0);
     83 }
     84 
     85 int
     86 main(int argc, char *argv[])
     87 {
     88 	struct fdescr *dsc;
     89 	Rune *delim;
     90 	size_t delimlen, i;
     91 	int seq = 0, ret = 0;
     92 	char *adelim = "\t";
     93 
     94 	ARGBEGIN {
     95 	case 's':
     96 		seq = 1;
     97 		break;
     98 	case 'd':
     99 		adelim = EARGF(usage());
    100 		unescape(adelim);
    101 		break;
    102 	default:
    103 		usage();
    104 	} ARGEND
    105 
    106 	if (!argc)
    107 		usage();
    108 
    109 	/* populate delimiters */
    110 	/* TODO: fix libutf to accept sizes */
    111 	delim = ereallocarray(NULL, utflen(adelim) + 1, sizeof(*delim));
    112 	if (!(delimlen = utftorunestr(adelim, delim)))
    113 		usage();
    114 
    115 	/* populate file list */
    116 	dsc = ereallocarray(NULL, argc, sizeof(*dsc));
    117 
    118 	for (i = 0; i < argc; i++) {
    119 		if (!strcmp(argv[i], "-")) {
    120 			argv[i] = "<stdin>";
    121 			dsc[i].fp = stdin;
    122 		} else if (!(dsc[i].fp = fopen(argv[i], "r"))) {
    123 			eprintf("fopen %s:", argv[i]);
    124 		}
    125 		dsc[i].name = argv[i];
    126 	}
    127 
    128 	if (seq) {
    129 		sequential(dsc, argc, delim, delimlen);
    130 	} else {
    131 		parallel(dsc, argc, delim, delimlen);
    132 	}
    133 
    134 	for (i = 0; i < argc; i++)
    135 		if (dsc[i].fp != stdin && fshut(dsc[i].fp, argv[i]))
    136 			ret |= fshut(dsc[i].fp, argv[i]);
    137 
    138 	ret |= fshut(stdin, "<stdin>") | fshut(stdout, "<stdout>");
    139 
    140 	return ret;
    141 }