After a short correspondence with Otto Moerbeek it turned out mallocarray() is only in the OpenBSD-Kernel, because the kernel- malloc doesn't have realloc. Userspace applications should rather use reallocarray with an explicit NULL-pointer. Assuming reallocarray() will become available in c-stdlibs in the next few years, we nip mallocarray() in the bud to allow an easy transition to a system-provided version when the day comes.
		
			
				
	
	
		
			136 lines
		
	
	
		
			2.3 KiB
		
	
	
	
		
			C
		
	
	
	
	
	
			
		
		
	
	
			136 lines
		
	
	
		
			2.3 KiB
		
	
	
	
		
			C
		
	
	
	
	
	
| /* See LICENSE file for copyright and license details. */
 | |
| #include <stdlib.h>
 | |
| #include <string.h>
 | |
| 
 | |
| #include "utf.h"
 | |
| #include "util.h"
 | |
| 
 | |
| struct fdescr {
 | |
| 	FILE *fp;
 | |
| 	const char *name;
 | |
| };
 | |
| 
 | |
| static void
 | |
| sequential(struct fdescr *dsc, int fdescrlen, Rune *delim, size_t delimlen)
 | |
| {
 | |
| 	Rune c, last;
 | |
| 	size_t i, d;
 | |
| 
 | |
| 	for (i = 0; i < fdescrlen; i++) {
 | |
| 		d = 0;
 | |
| 		last = 0;
 | |
| 
 | |
| 		while (efgetrune(&c, dsc[i].fp, dsc[i].name)) {
 | |
| 			if (last == '\n') {
 | |
| 				if (delim[d] != '\0')
 | |
| 					efputrune(&delim[d], stdout, "<stdout>");
 | |
| 				d = (d + 1) % delimlen;
 | |
| 			}
 | |
| 
 | |
| 			if (c != '\n')
 | |
| 				efputrune(&c, stdout, "<stdout>");
 | |
| 			last = c;
 | |
| 		}
 | |
| 
 | |
| 		if (last == '\n')
 | |
| 			efputrune(&last, stdout, "<stdout>");
 | |
| 	}
 | |
| }
 | |
| 
 | |
| static void
 | |
| parallel(struct fdescr *dsc, int fdescrlen, Rune *delim, size_t delimlen)
 | |
| {
 | |
| 	Rune c, d;
 | |
| 	size_t i, m;
 | |
| 	ssize_t last;
 | |
| 
 | |
| nextline:
 | |
| 	last = -1;
 | |
| 
 | |
| 	for (i = 0; i < fdescrlen; i++) {
 | |
| 		d = delim[i % delimlen];
 | |
| 		c = 0;
 | |
| 
 | |
| 		for (; efgetrune(&c, dsc[i].fp, dsc[i].name) ;) {
 | |
| 			for (m = last + 1; m < i; m++)
 | |
| 				efputrune(&(delim[m % delimlen]), stdout, "<stdout>");
 | |
| 			last = i;
 | |
| 			if (c == '\n') {
 | |
| 				if (i != fdescrlen - 1)
 | |
| 					c = d;
 | |
| 				efputrune(&c, stdout, "<stdout>");
 | |
| 				break;
 | |
| 			}
 | |
| 			efputrune(&c, stdout, "<stdout>");
 | |
| 		}
 | |
| 
 | |
| 		if (c == 0 && last != -1) {
 | |
| 			if (i == fdescrlen - 1)
 | |
| 				putchar('\n');
 | |
| 			else
 | |
| 				efputrune(&d, stdout, "<stdout>");
 | |
| 				last++;
 | |
| 		}
 | |
| 	}
 | |
| 	if (last != -1)
 | |
| 		goto nextline;
 | |
| }
 | |
| 
 | |
| static void
 | |
| usage(void)
 | |
| {
 | |
| 	eprintf("usage: %s [-s] [-d list] file ...\n", argv0);
 | |
| }
 | |
| 
 | |
| int
 | |
| main(int argc, char *argv[])
 | |
| {
 | |
| 	struct fdescr *dsc;
 | |
| 	Rune  *delim;
 | |
| 	size_t i, len;
 | |
| 	int    seq = 0;
 | |
| 	char  *adelim = "\t";
 | |
| 
 | |
| 	ARGBEGIN {
 | |
| 	case 's':
 | |
| 		seq = 1;
 | |
| 		break;
 | |
| 	case 'd':
 | |
| 		adelim = EARGF(usage());
 | |
| 		break;
 | |
| 	default:
 | |
| 		usage();
 | |
| 	} ARGEND;
 | |
| 
 | |
| 	if (argc == 0)
 | |
| 		usage();
 | |
| 
 | |
| 	/* populate delimiters */
 | |
| 	unescape(adelim);
 | |
| 	delim = ereallocarray(NULL, utflen(adelim) + 1, sizeof(*delim));
 | |
| 	len = utftorunestr(adelim, delim);
 | |
| 
 | |
| 	/* populate file list */
 | |
| 	dsc = ereallocarray(NULL, argc, sizeof(*dsc));
 | |
| 
 | |
| 	for (i = 0; i < argc; i++) {
 | |
| 		if (strcmp(argv[i], "-") == 0)
 | |
| 			dsc[i].fp = stdin;
 | |
| 		else
 | |
| 			dsc[i].fp = fopen(argv[i], "r");
 | |
| 		if (!dsc[i].fp)
 | |
| 			eprintf("fopen %s:", argv[i]);
 | |
| 		dsc[i].name = argv[i];
 | |
| 	}
 | |
| 
 | |
| 	if (seq)
 | |
| 		sequential(dsc, argc, delim, len);
 | |
| 	else
 | |
| 		parallel(dsc, argc, delim, len);
 | |
| 
 | |
| 	for (i = 0; i < argc; i++)
 | |
| 		fclose(dsc[i].fp);
 | |
| 
 | |
| 	return 0;
 | |
| }
 |