// Die with an error message if stdout has ferror set. void die_if_ferror_stdout(void) { die_if_ferror(stdout, bb_msg_standard_output); }
int uniq_main(int argc UNUSED_PARAM, char **argv) { FILE *in, *out; const char *s0, *e0, *s1, *e1, *input_filename; unsigned long dups; unsigned skip_fields, skip_chars, max_chars; unsigned opt; unsigned i; enum { OPT_c = 0x1, OPT_d = 0x2, OPT_u = 0x4, OPT_f = 0x8, OPT_s = 0x10, OPT_w = 0x20, }; skip_fields = skip_chars = 0; max_chars = INT_MAX; opt_complementary = "f+:s+:w+"; opt = getopt32(argv, "cduf:s:w:", &skip_fields, &skip_chars, &max_chars); argv += optind; input_filename = *argv; in = xgetoptfile_uniq_s(argv, 0); if (*argv) { ++argv; } out = xgetoptfile_uniq_s(argv, 2); if (*argv && argv[1]) { bb_show_usage(); } s1 = e1 = NULL; /* prime the pump */ do { s0 = s1; e0 = e1; dups = 0; /* gnu uniq ignores newlines */ while ((s1 = xmalloc_fgetline(in)) != NULL) { e1 = s1; for (i = skip_fields; i; i--) { e1 = skip_whitespace(e1); e1 = skip_non_whitespace(e1); } for (i = skip_chars; *e1 && i; i--) { ++e1; } if (!s0 || strncmp(e0, e1, max_chars)) { break; } ++dups; /* note: testing for overflow seems excessive. */ } if (s0) { if (!(opt & (OPT_d << !!dups))) { /* (if dups, opt & OPT_e) */ fprintf(out, "\0%ld " + (opt & 1), dups + 1); /* 1 == OPT_c */ fprintf(out, "%s\n", s0); } free((void *)s0); } } while (s1); die_if_ferror(in, input_filename); fflush_stdout_and_exit(EXIT_SUCCESS); }
int tee_main(int argc, char **argv) { const char *mode = "w\0a"; FILE **files; FILE **fp; char **names; char **np; char retval; #if ENABLE_FEATURE_TEE_USE_BLOCK_IO ssize_t c; # define buf bb_common_bufsiz1 #else int c; #endif retval = getopt32(argc, argv, "ia"); /* 'a' must be 2nd */ argc -= optind; argv += optind; mode += (retval & 2); /* Since 'a' is the 2nd option... */ if (retval & 1) { signal(SIGINT, SIG_IGN); /* TODO - switch to sigaction. */ } retval = EXIT_SUCCESS; /* gnu tee ignores SIGPIPE in case one of the output files is a pipe * that doesn't consume all its input. Good idea... */ signal(SIGPIPE, SIG_IGN); /* TODO - switch to sigaction. */ /* Allocate an array of FILE *'s, with one extra for a sentinal. */ fp = files = xzalloc(sizeof(FILE *) * (argc + 2)); np = names = argv - 1; files[0] = stdout; goto GOT_NEW_FILE; do { *fp = fopen_or_warn(*argv, mode); if (*fp == NULL) { retval = EXIT_FAILURE; continue; } *np = *argv++; GOT_NEW_FILE: setbuf(*fp++, NULL); /* tee must not buffer output. */ np++; } while (*argv); /* names[0] will be filled later */ #if ENABLE_FEATURE_TEE_USE_BLOCK_IO while ((c = safe_read(STDIN_FILENO, buf, BUFSIZ)) > 0) { fp = files; do fwrite(buf, 1, c, *fp++); while (*fp); } if (c < 0) { /* Make sure read errors are signaled. */ retval = EXIT_FAILURE; } #else setvbuf(stdout, NULL, _IONBF, 0); while ((c = getchar()) != EOF) { fp = files; do putc(c, *fp++); while (*fp); } #endif /* Now we need to check for i/o errors on stdin and the various * output files. Since we know that the first entry in the output * file table is stdout, we can save one "if ferror" test by * setting the first entry to stdin and checking stdout error * status with fflush_stdout_and_exit()... although fflush()ing * is unnecessary here. */ np = names; fp = files; names[0] = (char *) bb_msg_standard_input; files[0] = stdin; do { /* Now check for input and output errors. */ /* Checking ferror should be sufficient, but we may want to fclose. * If we do, remember not to close stdin! */ die_if_ferror(*fp++, *np++); } while (*fp); fflush_stdout_and_exit(retval); }
int uniq_main(int argc UNUSED_PARAM, char **argv) { const char *input_filename; unsigned skip_fields, skip_chars, max_chars; unsigned opt; char *cur_line; const char *cur_compare; enum { OPT_c = 0x1, OPT_d = 0x2, /* print only dups */ OPT_u = 0x4, /* print only uniq */ OPT_f = 0x8, OPT_s = 0x10, OPT_w = 0x20, OPT_i = 0x40, }; skip_fields = skip_chars = 0; max_chars = INT_MAX; opt = getopt32(argv, "cduf:+s:+w:+i", &skip_fields, &skip_chars, &max_chars); argv += optind; input_filename = argv[0]; if (input_filename) { const char *output; if (input_filename[0] != '-' || input_filename[1]) { close(STDIN_FILENO); /* == 0 */ xopen(input_filename, O_RDONLY); /* fd will be 0 */ } output = argv[1]; if (output) { if (argv[2]) bb_show_usage(); if (output[0] != '-' || output[1]) { // Won't work with "uniq - FILE" and closed stdin: //close(STDOUT_FILENO); //xopen(output, O_WRONLY | O_CREAT | O_TRUNC); xmove_fd(xopen(output, O_WRONLY | O_CREAT | O_TRUNC), STDOUT_FILENO); } } } cur_compare = cur_line = NULL; /* prime the pump */ do { unsigned i; unsigned long dups; char *old_line; const char *old_compare; old_line = cur_line; old_compare = cur_compare; dups = 0; /* gnu uniq ignores newlines */ while ((cur_line = xmalloc_fgetline(stdin)) != NULL) { cur_compare = cur_line; for (i = skip_fields; i; i--) { cur_compare = skip_whitespace(cur_compare); cur_compare = skip_non_whitespace(cur_compare); } for (i = skip_chars; *cur_compare && i; i--) { ++cur_compare; } if (!old_line) break; if ((opt & OPT_i) ? strncasecmp(old_compare, cur_compare, max_chars) : strncmp(old_compare, cur_compare, max_chars) ) { break; } free(cur_line); ++dups; /* testing for overflow seems excessive */ } if (old_line) { if (!(opt & (OPT_d << !!dups))) { /* (if dups, opt & OPT_u) */ if (opt & OPT_c) { /* %7lu matches GNU coreutils 6.9 */ printf("%7lu ", dups + 1); } puts(old_line); } free(old_line); } } while (cur_line); die_if_ferror(stdin, input_filename); fflush_stdout_and_exit(EXIT_SUCCESS); }