morpheus-base

morpheus base system
git clone git://git.2f30.org/morpheus-base
Log | Files | Refs

paste.c (3505B)


      1 /* See LICENSE file for copyright and license details. */
      2 #include <locale.h>
      3 #include <stdlib.h>
      4 #include <stdio.h>
      5 #include <string.h>
      6 #include <unistd.h>
      7 #include <wchar.h>
      8 
      9 #include "util.h"
     10 
     11 typedef struct {
     12 	FILE *fp;
     13 	const char *name;
     14 } Fdescr;
     15 
     16 static size_t unescape(wchar_t *);
     17 static wint_t in(Fdescr *);
     18 static void out(wchar_t);
     19 static void sequential(Fdescr *, int, const wchar_t *, size_t);
     20 static void parallel(Fdescr *, int, const wchar_t *, size_t);
     21 
     22 static void
     23 usage(void)
     24 {
     25 	eprintf("usage: %s [-s] [-d list] file...\n", argv0);
     26 }
     27 
     28 int
     29 main(int argc, char *argv[])
     30 {
     31 	const char *adelim = NULL;
     32 	int seq = 0;
     33 	wchar_t *delim = NULL;
     34 	size_t len;
     35 	Fdescr *dsc = NULL;
     36 	int i;
     37 
     38 	setlocale(LC_CTYPE, "");
     39 
     40 	ARGBEGIN {
     41 	case 's':
     42 		seq = 1;
     43 		break;
     44 	case 'd':
     45 		adelim = EARGF(usage());
     46 		break;
     47 	default:
     48 		usage();
     49 	} ARGEND;
     50 
     51 	if (argc == 0)
     52 		usage();
     53 
     54 	/* populate delimeters */
     55 	if (!adelim)
     56 		adelim = "\t";
     57 
     58 	len = mbstowcs(NULL, adelim, 0);
     59 	if (len == (size_t) - 1)
     60 		eprintf("invalid delimiter\n");
     61 
     62 	delim = emalloc((len + 1) * sizeof(*delim));
     63 
     64 	mbstowcs(delim, adelim, len);
     65 	len = unescape(delim);
     66 	if (len == 0)
     67 		eprintf("no delimiters specified\n");
     68 
     69 	/* populate file list */
     70 	dsc = emalloc(argc * sizeof(*dsc));
     71 
     72 	for (i = 0; i < argc; i++) {
     73 		if (strcmp(argv[i], "-") == 0)
     74 			dsc[i].fp = stdin;
     75 		else
     76 			dsc[i].fp = fopen(argv[i], "r");
     77 
     78 		if (!dsc[i].fp)
     79 			eprintf("can't open '%s':", argv[i]);
     80 
     81 		dsc[i].name = argv[i];
     82 	}
     83 
     84 	if (seq)
     85 		sequential(dsc, argc, delim, len);
     86 	else
     87 		parallel(dsc, argc, delim, len);
     88 
     89 	for (i = 0; i < argc; i++) {
     90 		if (dsc[i].fp != stdin)
     91 			(void)fclose(dsc[i].fp);
     92 	}
     93 
     94 	free(delim);
     95 	free(dsc);
     96 
     97 	return 0;
     98 }
     99 
    100 static size_t
    101 unescape(wchar_t *delim)
    102 {
    103 	wchar_t c;
    104 	size_t i;
    105 	size_t len;
    106 
    107 	for (i = 0, len = 0; (c = delim[i++]) != '\0'; len++) {
    108 		if (c == '\\') {
    109 			switch (delim[i++]) {
    110 			case 'n':
    111 				delim[len] = '\n';
    112 				break;
    113 			case 't':
    114 				delim[len] = '\t';
    115 				break;
    116 			case '0':
    117 				delim[len] = '\0';
    118 				break;
    119 			case '\\':
    120 				delim[len] = '\\';
    121 				break;
    122 			case '\0':
    123 			default:
    124 				/* POSIX: unspecified results */
    125 				return len;
    126 			}
    127 		} else
    128 			delim[len] = c;
    129 	}
    130 
    131 	return len;
    132 }
    133 
    134 static wint_t
    135 in(Fdescr *f)
    136 {
    137 	wint_t c = fgetwc(f->fp);
    138 
    139 	if (c == WEOF && ferror(f->fp))
    140 		eprintf("'%s' read error:", f->name);
    141 
    142 	return c;
    143 }
    144 
    145 static void
    146 out(wchar_t c)
    147 {
    148 	putwchar(c);
    149 	if (ferror(stdout))
    150 		eprintf("write error:");
    151 }
    152 
    153 static void
    154 sequential(Fdescr *dsc, int len, const wchar_t *delim, size_t cnt)
    155 {
    156 	int i;
    157 	size_t d;
    158 	wint_t c, last;
    159 
    160 	for (i = 0; i < len; i++) {
    161 		d = 0;
    162 		last = WEOF;
    163 
    164 		while ((c = in(&dsc[i])) != WEOF) {
    165 			if (last == '\n') {
    166 				if (delim[d] != '\0')
    167 					out(delim[d]);
    168 
    169 				d++;
    170 				d %= cnt;
    171 			}
    172 
    173 			if (c != '\n')
    174 				out((wchar_t)c);
    175 
    176 			last = c;
    177 		}
    178 
    179 		if (last == '\n')
    180 			out((wchar_t)last);
    181 	}
    182 }
    183 
    184 static void
    185 parallel(Fdescr *dsc, int len, const wchar_t *delim, size_t cnt)
    186 {
    187 	int last, i;
    188 	wint_t c, o;
    189 	wchar_t d;
    190 
    191 	do {
    192 		last = 0;
    193 		for (i = 0; i < len; i++) {
    194 			d = delim[i % cnt];
    195 
    196 			do {
    197 				o = in(&dsc[i]);
    198 				c = o;
    199 				switch (c) {
    200 				case WEOF:
    201 					if (last == 0)
    202 						break;
    203 
    204 					o = '\n';
    205 					/* fallthrough */
    206 				case '\n':
    207 					if (i != len - 1)
    208 						o = d;
    209 					break;
    210 				default:
    211 					break;
    212 				}
    213 
    214 				if (o != WEOF) {
    215 					/* pad with delimiters up to this point */
    216 					while (++last < i) {
    217 						if (d != '\0')
    218 							out(d);
    219 					}
    220 					out((wchar_t)o);
    221 				}
    222 			} while (c != '\n' && c != WEOF);
    223 		}
    224 	} while (last > 0);
    225 }