int sed_main(int argc UNUSED_PARAM, char **argv) { unsigned opt; llist_t *opt_e, *opt_f; char *opt_i; #if ENABLE_LONG_OPTS static const char sed_longopts[] ALIGN1 = /* name has_arg short */ "in-place\0" Optional_argument "i" "regexp-extended\0" No_argument "r" "quiet\0" No_argument "n" "silent\0" No_argument "n" "expression\0" Required_argument "e" "file\0" Required_argument "f"; #endif INIT_G(); /* destroy command strings on exit */ if (ENABLE_FEATURE_CLEAN_UP) atexit(sed_free_and_close_stuff); /* Lie to autoconf when it starts asking stupid questions. */ if (argv[1] && strcmp(argv[1], "--version") == 0) { puts("This is not GNU sed version 4.0"); return 0; } /* do normal option parsing */ opt_e = opt_f = NULL; opt_i = NULL; /* -i must be first, to match OPT_in_place definition */ /* -E is a synonym of -r: * GNU sed 4.2.1 mentions it in neither --help * nor manpage, but does recognize it. */ opt = getopt32long(argv, "^" "i::rEne:*f:*" "\0" "nn"/*count -n*/, sed_longopts, &opt_i, &opt_e, &opt_f, &G.be_quiet); /* counter for -n */ //argc -= optind; argv += optind; if (opt & OPT_in_place) { // -i die_func = cleanup_outname; } if (opt & (2|4)) G.regex_type |= REG_EXTENDED; // -r or -E //if (opt & 8) // G.be_quiet++; // -n (implemented with a counter instead) while (opt_e) { // -e add_cmd_block(llist_pop(&opt_e)); } while (opt_f) { // -f char *line; FILE *cmdfile; cmdfile = xfopen_stdin(llist_pop(&opt_f)); while ((line = xmalloc_fgetline(cmdfile)) != NULL) { add_cmd(line); free(line); } fclose_if_not_stdin(cmdfile); } /* if we didn't get a pattern from -e or -f, use argv[0] */ if (!(opt & 0x30)) { if (!*argv) bb_show_usage(); add_cmd_block(*argv++); } /* Flush any unfinished commands. */ add_cmd(""); /* By default, we write to stdout */ G.nonstdout = stdout; /* argv[0..(argc-1)] should be names of file to process. If no * files were specified or '-' was specified, take input from stdin. * Otherwise, we process all the files specified. */ G.input_file_list = argv; if (!argv[0]) { if (opt & OPT_in_place) bb_error_msg_and_die(bb_msg_requires_arg, "-i"); argv[0] = (char*)bb_msg_standard_input; /* G.last_input_file = 0; - already is */ } else { goto start; for (; *argv; argv++) { struct stat statbuf; int nonstdoutfd; sed_cmd_t *sed_cmd; G.last_input_file++; start: if (!(opt & OPT_in_place)) { if (LONE_DASH(*argv)) { *argv = (char*)bb_msg_standard_input; process_files(); } continue; } /* -i: process each FILE separately: */ if (stat(*argv, &statbuf) != 0) { bb_simple_perror_msg(*argv); G.exitcode = EXIT_FAILURE; G.current_input_file++; continue; } G.outname = xasprintf("%sXXXXXX", *argv); nonstdoutfd = xmkstemp(G.outname); G.nonstdout = xfdopen_for_write(nonstdoutfd); /* Set permissions/owner of output file */ /* chmod'ing AFTER chown would preserve suid/sgid bits, * but GNU sed 4.2.1 does not preserve them either */ fchmod(nonstdoutfd, statbuf.st_mode); fchown(nonstdoutfd, statbuf.st_uid, statbuf.st_gid); process_files(); fclose(G.nonstdout); G.nonstdout = stdout; if (opt_i) { char *backupname = xasprintf("%s%s", *argv, opt_i); xrename(*argv, backupname); free(backupname); } /* else unlink(*argv); - rename below does this */ xrename(G.outname, *argv); //TODO: rollback backup on error? free(G.outname); G.outname = NULL; /* Fix disabled range matches and mangled ",+N" ranges */ for (sed_cmd = G.sed_cmd_head; sed_cmd; sed_cmd = sed_cmd->next) { sed_cmd->beg_line = sed_cmd->beg_line_orig; sed_cmd->end_line = sed_cmd->end_line_orig; } } /* Here, to handle "sed 'cmds' nonexistent_file" case we did: * if (G.current_input_file[G.current_input_file] == NULL) * return G.exitcode; * but it's not needed since process_files() works correctly * in this case too. */ } process_files(); return G.exitcode; }
const char *fmt; int c1, c2; unsigned opt; int retval = 0; xfunc_error_retval = 2; /* 1 is returned if files are different. */ opt_complementary = "-1" IF_DESKTOP(":?4") IF_NOT_DESKTOP(":?2") ":l--s:s--l"; opt = getopt32(argv, opt_chars); argv += optind; filename1 = *argv; fp1 = xfopen_stdin(filename1); if (*++argv) { filename2 = *argv; #if ENABLE_DESKTOP if (*++argv) { skip1 = XATOOFF(*argv); if (*++argv) { skip2 = XATOOFF(*argv); } } #endif } fp2 = xfopen_stdin(filename2); if (fp1 == fp2) { /* Paranoia check... stdin == stdin? */
int patch_main(int argc UNUSED_PARAM, char **argv) { struct stat saved_stat; char *patch_line; FILE *patch_file; int patch_level; int ret = 0; char plus = '+'; unsigned opt; enum { OPT_R = (1 << 2), OPT_N = (1 << 3), /*OPT_f = (1 << 4), ignored */ /*OPT_E = (1 << 5), ignored, this is the default */ /*OPT_g = (1 << 6), ignored */ OPT_dry_run = (1 << 7) * ENABLE_LONG_OPTS, }; xfunc_error_retval = 2; { const char *p = "-1"; const char *i = "-"; /* compat */ #if ENABLE_LONG_OPTS static const char patch_longopts[] ALIGN1 = "strip\0" Required_argument "p" "input\0" Required_argument "i" "reverse\0" No_argument "R" "forward\0" No_argument "N" /* "Assume user knows what [s]he is doing, do not ask any questions": */ "force\0" No_argument "f" /*ignored*/ # if ENABLE_DESKTOP "remove-empty-files\0" No_argument "E" /*ignored*/ /* "Controls actions when a file is under RCS or SCCS control, * and does not exist or is read-only and matches the default version, * or when a file is under ClearCase control and does not exist..." * IOW: rather obscure option. * But Gentoo's portage does use -g0 */ "get\0" Required_argument "g" /*ignored*/ # endif "dry-run\0" No_argument "\xfd" # if ENABLE_DESKTOP "backup-if-mismatch\0" No_argument "\xfe" /*ignored*/ "no-backup-if-mismatch\0" No_argument "\xff" /*ignored*/ # endif ; applet_long_options = patch_longopts; #endif /* -f,-E,-g are ignored */ opt = getopt32(argv, "p:i:RN""fEg:", &p, &i, NULL); if (opt & OPT_R) plus = '-'; patch_level = xatoi(p); /* can be negative! */ patch_file = xfopen_stdin(i); } patch_line = xmalloc_fgetline(patch_file); while (patch_line) { FILE *src_stream; FILE *dst_stream; //char *old_filename; char *new_filename; char *backup_filename = NULL; unsigned src_cur_line = 1; unsigned dst_cur_line = 0; unsigned dst_beg_line; unsigned bad_hunk_count = 0; unsigned hunk_count = 0; smallint copy_trailing_lines_flag = 0; /* Skip everything upto the "---" marker * No need to parse the lines "Only in <dir>", and "diff <args>" */ do { /* Extract the filename ugsed before the patch was generated */ new_filename = extract_filename(patch_line, patch_level, "--- "); // was old_filename above patch_line = xmalloc_fgetline(patch_file); if (!patch_line) goto quit; } while (!new_filename); free(new_filename); // "source" filename is irrelevant new_filename = extract_filename(patch_line, patch_level, "+++ "); if (!new_filename) { bb_error_msg_and_die("invalid patch"); } /* Get access rights from the file to be patched */ if (stat(new_filename, &saved_stat) != 0) { char *slash = strrchr(new_filename, '/'); if (slash) { /* Create leading directories */ *slash = '\0'; bb_make_directory(new_filename, -1, FILEUTILS_RECUR); *slash = '/'; } src_stream = NULL; saved_stat.st_mode = 0644; } else if (!(opt & OPT_dry_run)) { backup_filename = xasprintf("%s.orig", new_filename); xrename(new_filename, backup_filename); src_stream = xfopen_for_read(backup_filename); } else src_stream = xfopen_for_read(new_filename); if (opt & OPT_dry_run) { dst_stream = xfopen_for_write("/dev/null"); } else { dst_stream = xfopen_for_write(new_filename); fchmod(fileno(dst_stream), saved_stat.st_mode); } printf("patching file %s\n", new_filename); /* Handle all hunks for this file */ patch_line = xmalloc_fgets(patch_file); while (patch_line) { unsigned count; unsigned src_beg_line; unsigned hunk_offset_start; unsigned src_last_line = 1; unsigned dst_last_line = 1; if ((sscanf(patch_line, "@@ -%u,%u +%u,%u", &src_beg_line, &src_last_line, &dst_beg_line, &dst_last_line) < 3) && (sscanf(patch_line, "@@ -%u +%u,%u", &src_beg_line, &dst_beg_line, &dst_last_line) < 2) ) { /* No more hunks for this file */ break; } if (plus != '+') { /* reverse patch */ unsigned tmp = src_last_line; src_last_line = dst_last_line; dst_last_line = tmp; tmp = src_beg_line; src_beg_line = dst_beg_line; dst_beg_line = tmp; } hunk_count++; if (src_beg_line && dst_beg_line) { /* Copy unmodified lines upto start of hunk */ /* src_beg_line will be 0 if it's a new file */ count = src_beg_line - src_cur_line; if (copy_lines(src_stream, dst_stream, count)) { bb_error_msg_and_die("bad src file"); } src_cur_line += count; dst_cur_line += count; copy_trailing_lines_flag = 1; } src_last_line += hunk_offset_start = src_cur_line; dst_last_line += dst_cur_line; while (1) { free(patch_line); patch_line = xmalloc_fgets(patch_file); if (patch_line == NULL) break; /* EOF */ if (!*patch_line) { /* whitespace-damaged patch with "" lines */ free(patch_line); patch_line = xstrdup(" "); } if ((*patch_line != '-') && (*patch_line != '+') && (*patch_line != ' ') ) { break; /* End of hunk */ } if (*patch_line != plus) { /* '-' or ' ' */ char *src_line = NULL; if (src_cur_line == src_last_line) break; if (src_stream) { src_line = xmalloc_fgets(src_stream); if (src_line) { int diff = strcmp(src_line, patch_line + 1); src_cur_line++; free(src_line); if (diff) src_line = NULL; } } /* Do not patch an already patched hunk with -N */ if (src_line == 0 && (opt & OPT_N)) { continue; } if (!src_line) { bb_error_msg("hunk #%u FAILED at %u", hunk_count, hunk_offset_start); bad_hunk_count++; break; } if (*patch_line != ' ') { /* '-' */ continue; } } if (dst_cur_line == dst_last_line) break; fputs(patch_line + 1, dst_stream); dst_cur_line++; } /* end of while loop handling one hunk */ } /* end of while loop handling one file */ /* Cleanup last patched file */ if (copy_trailing_lines_flag) { copy_lines(src_stream, dst_stream, (unsigned)(-1)); } if (src_stream) { fclose(src_stream); } fclose(dst_stream); if (bad_hunk_count) { ret = 1; bb_error_msg("%u out of %u hunk FAILED", bad_hunk_count, hunk_count); } else { /* It worked, we can remove the backup */ if (backup_filename) { unlink(backup_filename); } if (!(opt & OPT_dry_run) && ((dst_cur_line == 0) || (dst_beg_line == 0)) ) { /* The new patched file is empty, remove it */ xunlink(new_filename); // /* old_filename and new_filename may be the same file */ // unlink(old_filename); } } free(backup_filename); //free(old_filename); free(new_filename); } /* end of "while there are patch lines" */ quit: /* 0 = SUCCESS * 1 = Some hunks failed * 2 = More serious problems (exited earlier) */ return ret; }
int patch_main(int argc UNUSED_PARAM, char **argv) { struct stat saved_stat; char *patch_line; FILE *patch_file; int patch_level; int ret = 0; char plus = '+'; xfunc_error_retval = 2; { const char *p = "-1"; const char *i = "-"; /* compat */ if (getopt32(argv, "p:i:R", &p, &i) & 4) plus = '-'; patch_level = xatoi(p); /* can be negative! */ patch_file = xfopen_stdin(i); } patch_line = xmalloc_fgetline(patch_file); while (patch_line) { FILE *src_stream; FILE *dst_stream; //char *old_filename; char *new_filename; char *backup_filename; unsigned src_cur_line = 1; unsigned dst_cur_line = 0; unsigned dst_beg_line; unsigned bad_hunk_count = 0; unsigned hunk_count = 0; smallint copy_trailing_lines_flag = 0; /* Skip everything upto the "---" marker * No need to parse the lines "Only in <dir>", and "diff <args>" */ do { /* Extract the filename used before the patch was generated */ new_filename = extract_filename(patch_line, patch_level, "--- "); // was old_filename above patch_line = xmalloc_fgetline(patch_file); if (!patch_line) goto quit; } while (!new_filename); free(new_filename); // "source" filename is irrelevant new_filename = extract_filename(patch_line, patch_level, "+++ "); if (!new_filename) { bb_error_msg_and_die("invalid patch"); } /* Get access rights from the file to be patched */ if (stat(new_filename, &saved_stat) != 0) { char *slash = strrchr(new_filename, '/'); if (slash) { /* Create leading directories */ *slash = '\0'; bb_make_directory(new_filename, -1, FILEUTILS_RECUR); *slash = '/'; } backup_filename = NULL; src_stream = NULL; saved_stat.st_mode = 0644; } else { backup_filename = xasprintf("%s.orig", new_filename); xrename(new_filename, backup_filename); src_stream = xfopen_for_read(backup_filename); } dst_stream = xfopen_for_write(new_filename); fchmod(fileno(dst_stream), saved_stat.st_mode); printf("patching file %s\n", new_filename); /* Handle all hunks for this file */ patch_line = xmalloc_fgets(patch_file); while (patch_line) { unsigned count; unsigned src_beg_line; unsigned hunk_offset_start; unsigned src_last_line = 1; unsigned dst_last_line = 1; if ((sscanf(patch_line, "@@ -%d,%d +%d,%d", &src_beg_line, &src_last_line, &dst_beg_line, &dst_last_line) < 3) && (sscanf(patch_line, "@@ -%d +%d,%d", &src_beg_line, &dst_beg_line, &dst_last_line) < 2) ) { /* No more hunks for this file */ break; } if (plus != '+') { /* reverse patch */ unsigned tmp = src_last_line; src_last_line = dst_last_line; dst_last_line = tmp; tmp = src_beg_line; src_beg_line = dst_beg_line; dst_beg_line = tmp; } hunk_count++; if (src_beg_line && dst_beg_line) { /* Copy unmodified lines upto start of hunk */ /* src_beg_line will be 0 if it's a new file */ count = src_beg_line - src_cur_line; if (copy_lines(src_stream, dst_stream, count)) { bb_error_msg_and_die("bad src file"); } src_cur_line += count; dst_cur_line += count; copy_trailing_lines_flag = 1; } src_last_line += hunk_offset_start = src_cur_line; dst_last_line += dst_cur_line; while (1) { free(patch_line); patch_line = xmalloc_fgets(patch_file); if (patch_line == NULL) break; /* EOF */ if ((*patch_line != '-') && (*patch_line != '+') && (*patch_line != ' ') ) { break; /* End of hunk */ } if (*patch_line != plus) { /* '-' or ' ' */ char *src_line = NULL; if (src_cur_line == src_last_line) break; if (src_stream) { src_line = xmalloc_fgets(src_stream); if (src_line) { int diff = strcmp(src_line, patch_line + 1); src_cur_line++; free(src_line); if (diff) src_line = NULL; } } if (!src_line) { bb_error_msg("hunk #%u FAILED at %u", hunk_count, hunk_offset_start); bad_hunk_count++; break; } if (*patch_line != ' ') { /* '-' */ continue; } } if (dst_cur_line == dst_last_line) break; fputs(patch_line + 1, dst_stream); dst_cur_line++; } /* end of while loop handling one hunk */ } /* end of while loop handling one file */ /* Cleanup last patched file */ if (copy_trailing_lines_flag) { copy_lines(src_stream, dst_stream, (unsigned)(-1)); } if (src_stream) { fclose(src_stream); } fclose(dst_stream); if (bad_hunk_count) { ret = 1; bb_error_msg("%u out of %u hunk FAILED", bad_hunk_count, hunk_count); } else { /* It worked, we can remove the backup */ if (backup_filename) { unlink(backup_filename); } if ((dst_cur_line == 0) || (dst_beg_line == 0)) { /* The new patched file is empty, remove it */ xunlink(new_filename); // /* old_filename and new_filename may be the same file */ // unlink(old_filename); } } free(backup_filename); //free(old_filename); free(new_filename); } /* end of "while there are patch lines" */ quit: /* 0 = SUCCESS * 1 = Some hunks failed * 2 = More serious problems (exited earlier) */ return ret; }
int sort_main(int argc UNUSED_PARAM, char **argv) { FILE *fp, *outfile = stdout; char *line, **lines = NULL; char *str_ignored, *str_o, *str_t; llist_t *lst_k = NULL; int i, flag; int linecount = 0; xfunc_error_retval = 2; /* Parse command line options */ /* -o and -t can be given at most once */ opt_complementary = "o--o:t--t:" /* -t, -o: maximum one of each */ "k::"; /* -k takes list */ getopt32(argv, OPT_STR, &str_ignored, &str_ignored, &str_o, &lst_k, &str_t); #if ENABLE_FEATURE_SORT_BIG if (option_mask32 & FLAG_o) outfile = xfopen_for_write(str_o); if (option_mask32 & FLAG_t) { if (!str_t[0] || str_t[1]) bb_error_msg_and_die("bad -t parameter"); key_separator = str_t[0]; } /* parse sort key */ while (lst_k) { enum { FLAG_allowed_for_k = FLAG_n | /* Numeric sort */ FLAG_g | /* Sort using strtod() */ FLAG_M | /* Sort date */ FLAG_b | /* Ignore leading blanks */ FLAG_r | /* Reverse */ FLAG_d | /* Ignore !(isalnum()|isspace()) */ FLAG_f | /* Force uppercase */ FLAG_i | /* Ignore !isprint() */ 0 }; struct sort_key *key = add_key(); char *str_k = llist_pop(&lst_k); const char *temp2; i = 0; /* i==0 before comma, 1 after (-k3,6) */ while (*str_k) { /* Start of range */ /* Cannot use bb_strtou - suffix can be a letter */ key->range[2*i] = str2u(&str_k); if (*str_k == '.') { str_k++; key->range[2*i+1] = str2u(&str_k); } while (*str_k) { if (*str_k == ',' && !i++) { str_k++; break; } /* no else needed: fall through to syntax error because comma isn't in OPT_STR */ temp2 = strchr(OPT_STR, *str_k); if (!temp2) bb_error_msg_and_die("unknown key option"); flag = 1 << (temp2 - OPT_STR); if (flag & ~FLAG_allowed_for_k) bb_error_msg_and_die("unknown sort type"); /* b after ',' means strip _trailing_ space */ if (i && flag == FLAG_b) flag = FLAG_bb; key->flags |= flag; str_k++; } } } #endif /* global b strips leading and trailing spaces */ if (option_mask32 & FLAG_b) option_mask32 |= FLAG_bb; /* Open input files and read data */ argv += optind; if (!*argv) *--argv = (char*)"-"; do { /* coreutils 6.9 compat: abort on first open error, * do not continue to next file: */ fp = xfopen_stdin(*argv); for (;;) { line = GET_LINE(fp); if (!line) break; lines = xrealloc_vector(lines, 6, linecount); lines[linecount++] = line; } fclose_if_not_stdin(fp); } while (*++argv); #if ENABLE_FEATURE_SORT_BIG /* if no key, perform alphabetic sort */ if (!key_list) add_key()->range[0] = 1; /* handle -c */ if (option_mask32 & FLAG_c) { int j = (option_mask32 & FLAG_u) ? -1 : 0; for (i = 1; i < linecount; i++) if (compare_keys(&lines[i-1], &lines[i]) > j) { fprintf(stderr, "Check line %d\n", i); return EXIT_FAILURE; } return EXIT_SUCCESS; } #endif /* Perform the actual sort */ qsort(lines, linecount, sizeof(char *), compare_keys); /* handle -u */ if (option_mask32 & FLAG_u) { flag = 0; /* coreutils 6.3 drop lines for which only key is the same */ /* -- disabling last-resort compare... */ option_mask32 |= FLAG_s; for (i = 1; i < linecount; i++) { if (!compare_keys(&lines[flag], &lines[i])) free(lines[i]); else lines[++flag] = lines[i]; } if (linecount) linecount = flag+1; } /* Print it */ flag = (option_mask32 & FLAG_z) ? '\0' : '\n'; for (i = 0; i < linecount; i++) fprintf(outfile, "%s%c", lines[i], flag); fflush_stdout_and_exit(EXIT_SUCCESS); }
int sort_main(int argc UNUSED_PARAM, char **argv) { char *line, **lines; char *str_ignored, *str_o, *str_t; llist_t *lst_k = NULL; int i; int linecount; unsigned opts; xfunc_error_retval = 2; /* Parse command line options */ /* -o and -t can be given at most once */ opt_complementary = "o--o:t--t"; /* -t, -o: at most one of each */ opts = getopt32(argv, OPT_STR, &str_ignored, &str_ignored, &str_o, &lst_k, &str_t); /* global b strips leading and trailing spaces */ if (opts & FLAG_b) option_mask32 |= FLAG_bb; #if ENABLE_FEATURE_SORT_BIG if (opts & FLAG_t) { if (!str_t[0] || str_t[1]) bb_error_msg_and_die("bad -t parameter"); key_separator = str_t[0]; } /* note: below this point we use option_mask32, not opts, * since that reduces register pressure and makes code smaller */ /* Parse sort key */ while (lst_k) { enum { FLAG_allowed_for_k = FLAG_n | /* Numeric sort */ FLAG_g | /* Sort using strtod() */ FLAG_M | /* Sort date */ FLAG_b | /* Ignore leading blanks */ FLAG_r | /* Reverse */ FLAG_d | /* Ignore !(isalnum()|isspace()) */ FLAG_f | /* Force uppercase */ FLAG_i | /* Ignore !isprint() */ 0 }; struct sort_key *key = add_key(); char *str_k = llist_pop(&lst_k); i = 0; /* i==0 before comma, 1 after (-k3,6) */ while (*str_k) { /* Start of range */ /* Cannot use bb_strtou - suffix can be a letter */ key->range[2*i] = str2u(&str_k); if (*str_k == '.') { str_k++; key->range[2*i+1] = str2u(&str_k); } while (*str_k) { int flag; const char *idx; if (*str_k == ',' && !i++) { str_k++; break; } /* no else needed: fall through to syntax error because comma isn't in OPT_STR */ idx = strchr(OPT_STR, *str_k); if (!idx) bb_error_msg_and_die("unknown key option"); flag = 1 << (idx - OPT_STR); if (flag & ~FLAG_allowed_for_k) bb_error_msg_and_die("unknown sort type"); /* b after ',' means strip _trailing_ space */ if (i && flag == FLAG_b) flag = FLAG_bb; key->flags |= flag; str_k++; } } } #endif /* Open input files and read data */ argv += optind; if (!*argv) *--argv = (char*)"-"; linecount = 0; lines = NULL; do { /* coreutils 6.9 compat: abort on first open error, * do not continue to next file: */ FILE *fp = xfopen_stdin(*argv); for (;;) { line = GET_LINE(fp); if (!line) break; lines = xrealloc_vector(lines, 6, linecount); lines[linecount++] = line; } fclose_if_not_stdin(fp); } while (*++argv); #if ENABLE_FEATURE_SORT_BIG /* If no key, perform alphabetic sort */ if (!key_list) add_key()->range[0] = 1; /* Handle -c */ if (option_mask32 & FLAG_c) { int j = (option_mask32 & FLAG_u) ? -1 : 0; for (i = 1; i < linecount; i++) { if (compare_keys(&lines[i-1], &lines[i]) > j) { fprintf(stderr, "Check line %u\n", i); return EXIT_FAILURE; } } return EXIT_SUCCESS; } #endif /* Perform the actual sort */ qsort(lines, linecount, sizeof(lines[0]), compare_keys); /* Handle -u */ if (option_mask32 & FLAG_u) { int j = 0; /* coreutils 6.3 drop lines for which only key is the same */ /* -- disabling last-resort compare... */ option_mask32 |= FLAG_s; for (i = 1; i < linecount; i++) { if (compare_keys(&lines[j], &lines[i]) == 0) free(lines[i]); else lines[++j] = lines[i]; } if (linecount) linecount = j+1; } /* Print it */ #if ENABLE_FEATURE_SORT_BIG /* Open output file _after_ we read all input ones */ if (option_mask32 & FLAG_o) xmove_fd(xopen(str_o, O_WRONLY|O_CREAT|O_TRUNC), STDOUT_FILENO); #endif { int ch = (option_mask32 & FLAG_z) ? '\0' : '\n'; for (i = 0; i < linecount; i++) printf("%s%c", lines[i], ch); } fflush_stdout_and_exit(EXIT_SUCCESS); }