Rewrite parallel() so that it uses fgetln() instead of fgets() so that
horrid nasty things don't happen when the input lines are the same size as the buffer. Simplify by using an array of 'FILE *' instead of a linked list so that is possible to appease coverty (SID:1598) by freeing the memory. Also fclose() the input lines when they are consumed. Code still modifies optarg strings....
This commit is contained in:
parent
46940789af
commit
ec40cf92c2
@ -1,6 +1,7 @@
|
||||
# $NetBSD: Makefile,v 1.3 1997/01/09 14:43:19 tls Exp $
|
||||
# $NetBSD: Makefile,v 1.4 2006/03/31 18:59:52 dsl Exp $
|
||||
# from: @(#)Makefile 8.1 (Berkeley) 6/6/93
|
||||
|
||||
PROG= paste
|
||||
WARNS= 4
|
||||
|
||||
.include <bsd.prog.mk>
|
||||
|
@ -1,4 +1,4 @@
|
||||
/* $NetBSD: paste.c,v 1.8 2006/03/31 17:20:07 dsl Exp $ */
|
||||
/* $NetBSD: paste.c,v 1.9 2006/03/31 18:59:52 dsl Exp $ */
|
||||
|
||||
/*
|
||||
* Copyright (c) 1989, 1993
|
||||
@ -40,7 +40,7 @@ __COPYRIGHT("@(#) Copyright (c) 1989, 1993\n"
|
||||
|
||||
#ifndef lint
|
||||
/*static char sccsid[] = "from: @(#)paste.c 8.1 (Berkeley) 6/6/93";*/
|
||||
__RCSID("$NetBSD: paste.c,v 1.8 2006/03/31 17:20:07 dsl Exp $");
|
||||
__RCSID("$NetBSD: paste.c,v 1.9 2006/03/31 18:59:52 dsl Exp $");
|
||||
#endif /* not lint */
|
||||
|
||||
#include <sys/types.h>
|
||||
@ -53,13 +53,14 @@ __RCSID("$NetBSD: paste.c,v 1.8 2006/03/31 17:20:07 dsl Exp $");
|
||||
#include <string.h>
|
||||
#include <unistd.h>
|
||||
|
||||
void parallel(char **);
|
||||
void parallel(int, char **);
|
||||
void sequential(char **);
|
||||
int tr(char *);
|
||||
void usage(void);
|
||||
|
||||
char *delim;
|
||||
int delimcnt;
|
||||
char dflt_delim[] = "\t";
|
||||
char *delim = dflt_delim;
|
||||
int delimcnt = 1;
|
||||
|
||||
int
|
||||
main(int argc, char **argv)
|
||||
@ -67,10 +68,11 @@ main(int argc, char **argv)
|
||||
int ch, seq;
|
||||
|
||||
seq = 0;
|
||||
while ((ch = getopt(argc, argv, "d:s")) != -1)
|
||||
while ((ch = getopt(argc, argv, "d:s")) != -1) {
|
||||
switch (ch) {
|
||||
case 'd':
|
||||
delimcnt = tr(delim = optarg);
|
||||
delim = strdup(optarg);
|
||||
delimcnt = tr(delim);
|
||||
break;
|
||||
case 's':
|
||||
seq = 1;
|
||||
@ -79,93 +81,81 @@ main(int argc, char **argv)
|
||||
default:
|
||||
usage();
|
||||
}
|
||||
}
|
||||
argc -= optind;
|
||||
argv += optind;
|
||||
|
||||
if (!delim) {
|
||||
delimcnt = 1;
|
||||
delim = "\t";
|
||||
}
|
||||
|
||||
if (seq)
|
||||
sequential(argv);
|
||||
else
|
||||
parallel(argv);
|
||||
parallel(argc, argv);
|
||||
exit(0);
|
||||
}
|
||||
|
||||
typedef struct _list {
|
||||
struct _list *next;
|
||||
FILE *fp;
|
||||
int cnt;
|
||||
char *name;
|
||||
} LIST;
|
||||
|
||||
void
|
||||
parallel(char **argv)
|
||||
parallel(int argc, char **argv)
|
||||
{
|
||||
LIST *lp;
|
||||
int cnt;
|
||||
char ch, *p;
|
||||
LIST *head, *tmp;
|
||||
int opencnt, output;
|
||||
char buf[_POSIX2_LINE_MAX + 1];
|
||||
char ch, *dp, *line;
|
||||
FILE **fpp, *fp;
|
||||
size_t line_len;
|
||||
int cnt, output;
|
||||
|
||||
tmp = NULL;
|
||||
for (cnt = 0, head = NULL; (p = *argv) != NULL; ++argv, ++cnt) {
|
||||
if (!(lp = (LIST *)malloc((u_int)sizeof(LIST))))
|
||||
err(1, "malloc");
|
||||
if (p[0] == '-' && !p[1])
|
||||
lp->fp = stdin;
|
||||
else if (!(lp->fp = fopen(p, "r")))
|
||||
err(1, "%s", p);
|
||||
lp->next = NULL;
|
||||
lp->cnt = cnt;
|
||||
lp->name = p;
|
||||
if (!head)
|
||||
head = tmp = lp;
|
||||
else {
|
||||
tmp->next = lp;
|
||||
tmp = lp;
|
||||
}
|
||||
fpp = calloc(argc, sizeof *fpp);
|
||||
if (fpp == NULL)
|
||||
err(1, "calloc");
|
||||
|
||||
for (cnt = 0; cnt < argc; cnt++) {
|
||||
if (strcmp(argv[cnt], "-") == 0)
|
||||
fpp[cnt] = stdin;
|
||||
else if (!(fpp[cnt] = fopen(argv[cnt], "r")))
|
||||
err(1, "%s", argv[cnt]);
|
||||
}
|
||||
|
||||
for (opencnt = cnt; opencnt;) {
|
||||
for (output = 0, lp = head; lp; lp = lp->next) {
|
||||
if (!lp->fp) {
|
||||
if (output && lp->cnt &&
|
||||
(ch = delim[(lp->cnt - 1) % delimcnt]))
|
||||
putchar(ch);
|
||||
for (;;) {
|
||||
/* Start with the NUL at the end of 'delim' ... */
|
||||
dp = delim + delimcnt;
|
||||
output = 0;
|
||||
for (cnt = 0; cnt < argc; cnt++) {
|
||||
fp = fpp[cnt];
|
||||
if (fp == NULL)
|
||||
continue;
|
||||
line = fgetln(fp, &line_len);
|
||||
if (line == NULL) {
|
||||
/* Assume EOF */
|
||||
if (fp != stdin)
|
||||
fclose(fp);
|
||||
fpp[cnt] = NULL;
|
||||
continue;
|
||||
}
|
||||
if (!fgets(buf, sizeof(buf), lp->fp)) {
|
||||
if (!--opencnt)
|
||||
break;
|
||||
lp->fp = NULL;
|
||||
if (output && lp->cnt &&
|
||||
(ch = delim[(lp->cnt - 1) % delimcnt]))
|
||||
/* Output enough separators to catch up */
|
||||
do {
|
||||
ch = *dp++;
|
||||
if (ch)
|
||||
putchar(ch);
|
||||
continue;
|
||||
}
|
||||
if (!(p = strchr(buf, '\n')))
|
||||
err(1, "%s: input line too long.", lp->name);
|
||||
*p = '\0';
|
||||
/*
|
||||
* make sure that we don't print any delimiters
|
||||
* unless there's a non-empty file.
|
||||
*/
|
||||
if (!output) {
|
||||
output = 1;
|
||||
for (cnt = 0; cnt < lp->cnt; ++cnt)
|
||||
if ((ch = delim[cnt % delimcnt]) != 0)
|
||||
putchar(ch);
|
||||
} else if ((ch = delim[(lp->cnt - 1) % delimcnt]) != 0)
|
||||
if (dp >= delim + delimcnt)
|
||||
dp = delim;
|
||||
} while (++output <= cnt);
|
||||
/* Remove any trailing newline - check for last line */
|
||||
if (line[line_len - 1] == '\n')
|
||||
line_len--;
|
||||
printf("%.*s", line_len, line);
|
||||
}
|
||||
|
||||
if (!output)
|
||||
break;
|
||||
|
||||
/* Add separators to end of line */
|
||||
while (++output <= cnt) {
|
||||
ch = *dp++;
|
||||
if (ch)
|
||||
putchar(ch);
|
||||
(void)printf("%s", buf);
|
||||
if (dp >= delim + delimcnt)
|
||||
dp = delim;
|
||||
}
|
||||
if (output)
|
||||
putchar('\n');
|
||||
putchar('\n');
|
||||
}
|
||||
|
||||
free(fpp);
|
||||
}
|
||||
|
||||
void
|
||||
|
Loading…
Reference in New Issue
Block a user