| File: | src/usr.bin/split/split.c |
| Warning: | line 133, column 2 Value stored to 'argc' is never read |
Press '?' to see keyboard shortcuts
Keyboard shortcuts:
| 1 | /* $OpenBSD: split.c,v 1.23 2021/11/28 19:28:42 deraadt Exp $ */ |
| 2 | /* $NetBSD: split.c,v 1.5 1995/08/31 22:22:05 jtc Exp $ */ |
| 3 | |
| 4 | /* |
| 5 | * Copyright (c) 1987, 1993, 1994 |
| 6 | * The Regents of the University of California. All rights reserved. |
| 7 | * |
| 8 | * Redistribution and use in source and binary forms, with or without |
| 9 | * modification, are permitted provided that the following conditions |
| 10 | * are met: |
| 11 | * 1. Redistributions of source code must retain the above copyright |
| 12 | * notice, this list of conditions and the following disclaimer. |
| 13 | * 2. Redistributions in binary form must reproduce the above copyright |
| 14 | * notice, this list of conditions and the following disclaimer in the |
| 15 | * documentation and/or other materials provided with the distribution. |
| 16 | * 3. Neither the name of the University nor the names of its contributors |
| 17 | * may be used to endorse or promote products derived from this software |
| 18 | * without specific prior written permission. |
| 19 | * |
| 20 | * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND |
| 21 | * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE |
| 22 | * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE |
| 23 | * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE |
| 24 | * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL |
| 25 | * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS |
| 26 | * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) |
| 27 | * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT |
| 28 | * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY |
| 29 | * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF |
| 30 | * SUCH DAMAGE. |
| 31 | */ |
| 32 | |
| 33 | #include <sys/types.h> |
| 34 | |
| 35 | #include <ctype.h> |
| 36 | #include <err.h> |
| 37 | #include <fcntl.h> |
| 38 | #include <limits.h> |
| 39 | #include <stdio.h> |
| 40 | #include <stdlib.h> |
| 41 | #include <string.h> |
| 42 | #include <unistd.h> |
| 43 | #include <regex.h> |
| 44 | |
| 45 | #define _MAXBSIZE(64 * 1024) (64 * 1024) |
| 46 | |
| 47 | #define DEFLINE1000 1000 /* Default num lines per file. */ |
| 48 | |
| 49 | ssize_t bytecnt; /* Byte count to split on. */ |
| 50 | long numlines; /* Line count to split on. */ |
| 51 | int file_open; /* If a file open. */ |
| 52 | int ifd = -1, ofd = -1; /* Input/output file descriptors. */ |
| 53 | char bfr[_MAXBSIZE(64 * 1024)]; /* I/O buffer. */ |
| 54 | char fname[PATH_MAX1024]; /* File name prefix. */ |
| 55 | regex_t rgx; |
| 56 | int pflag; |
| 57 | int sufflen = 2; /* File name suffix length. */ |
| 58 | |
| 59 | void newfile(void); |
| 60 | void split1(void); |
| 61 | void split2(void); |
| 62 | __dead__attribute__((__noreturn__)) void usage(void); |
| 63 | |
| 64 | int |
| 65 | main(int argc, char *argv[]) |
| 66 | { |
| 67 | int ch, scale; |
| 68 | char *ep, *p; |
| 69 | const char *errstr; |
| 70 | |
| 71 | if (pledge("stdio rpath wpath cpath", NULL((void *)0)) == -1) |
| 72 | err(1, "pledge"); |
| 73 | |
| 74 | while ((ch = getopt(argc, argv, "0123456789a:b:l:p:-")) != -1) |
| 75 | switch (ch) { |
| 76 | case '0': case '1': case '2': case '3': case '4': |
| 77 | case '5': case '6': case '7': case '8': case '9': |
| 78 | /* |
| 79 | * Undocumented kludge: split was originally designed |
| 80 | * to take a number after a dash. |
| 81 | */ |
| 82 | if (numlines == 0) { |
| 83 | p = argv[optind - 1]; |
| 84 | if (p[0] == '-' && p[1] == ch && !p[2]) |
| 85 | numlines = strtol(++p, &ep, 10); |
| 86 | else |
| 87 | numlines = |
| 88 | strtol(argv[optind] + 1, &ep, 10); |
| 89 | if (numlines <= 0 || *ep) |
| 90 | errx(1, "%s: illegal line count", |
| 91 | optarg); |
| 92 | } |
| 93 | break; |
| 94 | case '-': /* Undocumented: historic stdin flag. */ |
| 95 | if (ifd != -1) |
| 96 | usage(); |
| 97 | ifd = 0; |
| 98 | break; |
| 99 | case 'a': /* suffix length. */ |
| 100 | sufflen = strtonum(optarg, 1, NAME_MAX255, &errstr); |
| 101 | if (errstr) |
| 102 | errx(1, "%s: %s", optarg, errstr); |
| 103 | break; |
| 104 | case 'b': /* Byte count. */ |
| 105 | if ((bytecnt = strtol(optarg, &ep, 10)) <= 0 || |
| 106 | (*ep != '\0' && *ep != 'k' && *ep != 'm')) |
| 107 | errx(1, "%s: illegal byte count", optarg); |
| 108 | if (*ep == 'k') |
| 109 | scale = 1024; |
| 110 | else if (*ep == 'm') |
| 111 | scale = 1048576; |
| 112 | else |
| 113 | scale = 1; |
| 114 | if (bytecnt > SSIZE_MAX9223372036854775807L / scale) |
| 115 | errx(1, "%s: byte count too large", optarg); |
| 116 | bytecnt *= scale; |
| 117 | break; |
| 118 | case 'p' : /* pattern matching. */ |
| 119 | if (regcomp(&rgx, optarg, REG_EXTENDED0001|REG_NOSUB0004) != 0) |
| 120 | errx(1, "%s: illegal regexp", optarg); |
| 121 | pflag = 1; |
| 122 | break; |
| 123 | case 'l': /* Line count. */ |
| 124 | if (numlines != 0) |
| 125 | usage(); |
| 126 | if ((numlines = strtol(optarg, &ep, 10)) <= 0 || *ep) |
| 127 | errx(1, "%s: illegal line count", optarg); |
| 128 | break; |
| 129 | default: |
| 130 | usage(); |
| 131 | } |
| 132 | argv += optind; |
| 133 | argc -= optind; |
Value stored to 'argc' is never read | |
| 134 | |
| 135 | if (*argv != NULL((void *)0)) |
| 136 | if (ifd == -1) { /* Input file. */ |
| 137 | if ((ifd = open(*argv, O_RDONLY0x0000)) < 0) |
| 138 | err(1, "%s", *argv); |
| 139 | ++argv; |
| 140 | } |
| 141 | if (*argv != NULL((void *)0)) /* File name prefix. */ |
| 142 | (void)strlcpy(fname, *argv++, sizeof(fname)); |
| 143 | if (*argv != NULL((void *)0)) |
| 144 | usage(); |
| 145 | |
| 146 | if (strlen(fname) + sufflen >= sizeof(fname)) |
| 147 | errx(1, "suffix is too long"); |
| 148 | if (pflag && (numlines != 0 || bytecnt != 0)) |
| 149 | usage(); |
| 150 | |
| 151 | if (numlines == 0) |
| 152 | numlines = DEFLINE1000; |
| 153 | else if (bytecnt != 0) |
| 154 | usage(); |
| 155 | |
| 156 | if (ifd == -1) /* Stdin by default. */ |
| 157 | ifd = 0; |
| 158 | |
| 159 | if (bytecnt) { |
| 160 | split1(); |
| 161 | exit (0); |
| 162 | } |
| 163 | split2(); |
| 164 | if (pflag) |
| 165 | regfree(&rgx); |
| 166 | exit(0); |
| 167 | } |
| 168 | |
| 169 | /* |
| 170 | * split1 -- |
| 171 | * Split the input by bytes. |
| 172 | */ |
| 173 | void |
| 174 | split1(void) |
| 175 | { |
| 176 | ssize_t bcnt, dist, len; |
| 177 | char *C; |
| 178 | |
| 179 | for (bcnt = 0;;) |
| 180 | switch ((len = read(ifd, bfr, sizeof(bfr)))) { |
| 181 | case 0: |
| 182 | exit(0); |
| 183 | case -1: |
| 184 | err(1, "read"); |
| 185 | /* NOTREACHED */ |
| 186 | default: |
| 187 | if (!file_open) |
| 188 | newfile(); |
| 189 | if (bcnt + len >= bytecnt) { |
| 190 | dist = bytecnt - bcnt; |
| 191 | if (write(ofd, bfr, dist) != dist) |
| 192 | err(1, "write"); |
| 193 | len -= dist; |
| 194 | for (C = bfr + dist; len >= bytecnt; |
| 195 | len -= bytecnt, C += bytecnt) { |
| 196 | newfile(); |
| 197 | if (write(ofd, C, bytecnt) != bytecnt) |
| 198 | err(1, "write"); |
| 199 | } |
| 200 | if (len != 0) { |
| 201 | newfile(); |
| 202 | if (write(ofd, C, len) != len) |
| 203 | err(1, "write"); |
| 204 | } else |
| 205 | file_open = 0; |
| 206 | bcnt = len; |
| 207 | } else { |
| 208 | bcnt += len; |
| 209 | if (write(ofd, bfr, len) != len) |
| 210 | err(1, "write"); |
| 211 | } |
| 212 | } |
| 213 | } |
| 214 | |
| 215 | /* |
| 216 | * split2 -- |
| 217 | * Split the input by lines. |
| 218 | */ |
| 219 | void |
| 220 | split2(void) |
| 221 | { |
| 222 | long lcnt = 0; |
| 223 | FILE *infp; |
| 224 | |
| 225 | /* Stick a stream on top of input file descriptor */ |
| 226 | if ((infp = fdopen(ifd, "r")) == NULL((void *)0)) |
| 227 | err(1, "fdopen"); |
| 228 | |
| 229 | /* Process input one line at a time */ |
| 230 | while (fgets(bfr, sizeof(bfr), infp) != NULL((void *)0)) { |
| 231 | const int len = strlen(bfr); |
| 232 | |
| 233 | if (len == 0) |
| 234 | continue; |
| 235 | |
| 236 | /* If line is too long to deal with, just write it out */ |
| 237 | if (bfr[len - 1] != '\n') |
| 238 | goto writeit; |
| 239 | |
| 240 | /* Check if we need to start a new file */ |
| 241 | if (pflag) { |
| 242 | regmatch_t pmatch; |
| 243 | |
| 244 | pmatch.rm_so = 0; |
| 245 | pmatch.rm_eo = len - 1; |
| 246 | if (regexec(&rgx, bfr, 0, &pmatch, REG_STARTEND00004) == 0) |
| 247 | newfile(); |
| 248 | } else if (lcnt++ == numlines) { |
| 249 | newfile(); |
| 250 | lcnt = 1; |
| 251 | } |
| 252 | |
| 253 | writeit: |
| 254 | /* Open output file if needed */ |
| 255 | if (!file_open) |
| 256 | newfile(); |
| 257 | |
| 258 | /* Write out line */ |
| 259 | if (write(ofd, bfr, len) != len) |
| 260 | err(1, "write"); |
| 261 | } |
| 262 | |
| 263 | /* EOF or error? */ |
| 264 | if (ferror(infp)(!__isthreaded ? (((infp)->_flags & 0x0040) != 0) : (ferror )(infp))) |
| 265 | err(1, "read"); |
| 266 | else |
| 267 | exit(0); |
| 268 | } |
| 269 | |
| 270 | /* |
| 271 | * newfile -- |
| 272 | * Open a new output file. |
| 273 | */ |
| 274 | void |
| 275 | newfile(void) |
| 276 | { |
| 277 | static char *suffix, *sufftail; |
| 278 | char *sptr; |
| 279 | |
| 280 | if (ofd == -1) { |
| 281 | ofd = fileno(stdout)(!__isthreaded ? (((&__sF[1]))->_file) : (fileno)((& __sF[1]))); |
| 282 | if (*fname == '\0') { |
| 283 | *fname = 'x'; /* no name specified, use 'x' */ |
| 284 | memset(fname + 1, 'a', sufflen); |
| 285 | suffix = fname; |
| 286 | sufflen++; /* treat 'x' as part of suffix */ |
| 287 | } else { |
| 288 | suffix = fname + strlen(fname); |
| 289 | memset(suffix, 'a', sufflen); |
| 290 | } |
| 291 | suffix[sufflen] = '\0'; |
| 292 | sufftail = suffix + sufflen - 1; |
| 293 | } else { |
| 294 | for (sptr = sufftail; sptr >= suffix; sptr--) { |
| 295 | if (*sptr != 'z') { |
| 296 | (*sptr)++; |
| 297 | break; |
| 298 | } else |
| 299 | *sptr = 'a'; |
| 300 | } |
| 301 | if (sptr < suffix) |
| 302 | errx(1, "too many files"); |
| 303 | } |
| 304 | |
| 305 | if (!freopen(fname, "w", stdout(&__sF[1]))) |
| 306 | err(1, "%s", fname); |
| 307 | file_open = 1; |
| 308 | } |
| 309 | |
| 310 | __dead__attribute__((__noreturn__)) void |
| 311 | usage(void) |
| 312 | { |
| 313 | extern char *__progname; |
| 314 | |
| 315 | (void)fprintf(stderr(&__sF[2]), "usage: %s [-a suffix_length]\n" |
| 316 | " [-b byte_count[k|m] | -l line_count | -p pattern] " |
| 317 | "[file [name]]\n", __progname); |
| 318 | exit(1); |
| 319 | } |