diff options
| author | dsl <dsl@NetBSD.org> | 2006-03-31 18:59:52 +0000 |
|---|---|---|
| committer | dsl <dsl@NetBSD.org> | 2006-03-31 18:59:52 +0000 |
| commit | ec40cf92c27bc21cb296108589fd88eafcd65703 (patch) | |
| tree | caf16993c1a124dfe33b76d55cf2beaab835f517 /usr.bin/paste | |
| parent | 46940789afe8deda30a7a96d9d4c061ec9b1ee02 (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/Makefile | 3 | ||||
| -rw-r--r-- | usr.bin/paste/paste.c | 140 |
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 |
