summaryrefslogtreecommitdiff
path: root/usr.bin/paste
diff options
context:
space:
mode:
authordsl <dsl@NetBSD.org>2006-03-31 18:59:52 +0000
committerdsl <dsl@NetBSD.org>2006-03-31 18:59:52 +0000
commitec40cf92c27bc21cb296108589fd88eafcd65703 (patch)
treecaf16993c1a124dfe33b76d55cf2beaab835f517 /usr.bin/paste
parent46940789afe8deda30a7a96d9d4c061ec9b1ee02 (diff)
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....
Diffstat (limited to 'usr.bin/paste')
-rw-r--r--usr.bin/paste/Makefile3
-rw-r--r--usr.bin/paste/paste.c140
2 files changed, 67 insertions, 76 deletions
diff --git a/usr.bin/paste/Makefile b/usr.bin/paste/Makefile
index 1650a788253..1c8ac072ba7 100644
--- a/usr.bin/paste/Makefile
+++ b/usr.bin/paste/Makefile
@@ -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>
diff --git a/usr.bin/paste/paste.c b/usr.bin/paste/paste.c
index 507b3007c22..45e0627645a 100644
--- a/usr.bin/paste/paste.c
+++ b/usr.bin/paste/paste.c
@@ -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];
-
- 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;
- }
+ char ch, *dp, *line;
+ FILE **fpp, *fp;
+ size_t line_len;
+ int cnt, output;
+
+ 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;
- }
- if (!fgets(buf, sizeof(buf), lp->fp)) {
- if (!--opencnt)
- break;
- lp->fp = NULL;
- if (output && lp->cnt &&
- (ch = delim[(lp->cnt - 1) % delimcnt]))
- putchar(ch);
+ line = fgetln(fp, &line_len);
+ if (line == NULL) {
+ /* Assume EOF */
+ if (fp != stdin)
+ fclose(fp);
+ fpp[cnt] = NULL;
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)
+ /* Output enough separators to catch up */
+ do {
+ ch = *dp++;
+ if (ch)
+ putchar(ch);
+ 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