📄 sort.c
字号:
i = n_temp_files; for (node = temphead.next; i > 0; node = node->next) tempfiles[--i] = node->name; merge (tempfiles, n_temp_files, ofp, output_file); free ((char *) tempfiles); }}/* Insert key KEY at the end of the list (`keyhead'). */static voidinsertkey (struct keyfield *key){ struct keyfield *k = &keyhead; while (k->next) k = k->next; k->next = key; key->next = NULL;}static voidbadfieldspec (const char *s){ error (SORT_FAILURE, 0, _("invalid field specification `%s'"), s);}/* Handle interrupts and hangups. */static voidsighandler (int sig){#ifdef SA_INTERRUPT struct sigaction sigact; sigact.sa_handler = SIG_DFL; sigemptyset (&sigact.sa_mask); sigact.sa_flags = 0; sigaction (sig, &sigact, NULL);#else /* !SA_INTERRUPT */ signal (sig, SIG_DFL);#endif /* SA_INTERRUPT */ cleanup ();#ifdef __MINGW32__ raise (sig);#else kill (getpid (), sig);#endif}/* Set the ordering options for KEY specified in S. Return the address of the first character in S that is not a valid ordering option. BLANKTYPE is the kind of blanks that 'b' should skip. */static char *set_ordering (register const char *s, struct keyfield *key, enum blanktype blanktype){ while (*s) { switch (*s) { case 'b': if (blanktype == bl_start || blanktype == bl_both) key->skipsblanks = 1; if (blanktype == bl_end || blanktype == bl_both) key->skipeblanks = 1; break; case 'd': key->ignore = nondictionary; break; case 'f': key->translate = fold_toupper; break; case 'g': key->general_numeric = 1; break; case 'i': key->ignore = nonprinting; break; case 'M': key->month = 1; break; case 'n': key->numeric = 1; break; case 'r': key->reverse = 1; break; default: return (char *) s; } ++s; } return (char *) s;}static voidkey_init (struct keyfield *key){ memset (key, 0, sizeof (*key)); key->eword = -1;}intmain (int argc, char **argv){ struct keyfield *key = NULL, gkey; char *s; int i, t, t2; int checkonly = 0, mergeonly = 0, nfiles = 0; char *minus = "-", *outfile = minus, **files, *tmp; FILE *ofp;#ifdef SA_INTERRUPT struct sigaction oldact, newact;#endif /* SA_INTERRUPT */ program_name = argv[0]; setlocale (LC_ALL, ""); bindtextdomain (PACKAGE, LOCALEDIR); textdomain (PACKAGE);#ifdef ENABLE_NLS hard_LC_COLLATE = hard_locale (LC_COLLATE); hard_LC_CTYPE = hard_locale (LC_CTYPE);# if HAVE_NL_LANGINFO hard_LC_TIME = hard_locale (LC_TIME);# endif /* Let's get locale's representation of the decimal point */ { struct lconv *lconvp = localeconv (); /* If the locale doesn't define a decimal point, or if the decimal point is multibyte, use the C decimal point. We don't support multibyte decimal points yet. */ decimal_point = *lconvp->decimal_point; if (! decimal_point || lconvp->decimal_point[1]) decimal_point = C_DECIMAL_POINT; /* We don't support multibyte thousands separators yet. */ th_sep = *lconvp->thousands_sep; if (! th_sep || lconvp->thousands_sep[1]) th_sep = CHAR_MAX + 1; }#endif /* NLS */ parse_long_options (argc, argv, PROGRAM_NAME, GNU_PACKAGE, VERSION, AUTHORS, usage); have_read_stdin = 0; inittables (); temp_dir = getenv ("TMPDIR"); if (temp_dir == NULL) temp_dir = DEFAULT_TMPDIR; /* Change the way xmalloc and xrealloc fail. */ xalloc_exit_failure = SORT_FAILURE; xalloc_fail_func = cleanup;#ifdef SA_INTERRUPT newact.sa_handler = sighandler; sigemptyset (&newact.sa_mask); newact.sa_flags = 0; sigaction (SIGINT, NULL, &oldact); if (oldact.sa_handler != SIG_IGN) sigaction (SIGINT, &newact, NULL); sigaction (SIGHUP, NULL, &oldact); if (oldact.sa_handler != SIG_IGN) sigaction (SIGHUP, &newact, NULL); sigaction (SIGPIPE, NULL, &oldact); if (oldact.sa_handler != SIG_IGN) sigaction (SIGPIPE, &newact, NULL); sigaction (SIGTERM, NULL, &oldact); if (oldact.sa_handler != SIG_IGN) sigaction (SIGTERM, &newact, NULL);#else /* !SA_INTERRUPT */ if (signal (SIGINT, SIG_IGN) != SIG_IGN) signal (SIGINT, sighandler);#ifdef SIGHUP if (signal (SIGHUP, SIG_IGN) != SIG_IGN) signal (SIGHUP, sighandler);#endif#ifdef SIGPIPE if (signal (SIGPIPE, SIG_IGN) != SIG_IGN) signal (SIGPIPE, sighandler);#endif if (signal (SIGTERM, SIG_IGN) != SIG_IGN) signal (SIGTERM, sighandler);#endif /* !SA_INTERRUPT */ gkey.sword = gkey.eword = -1; gkey.ignore = NULL; gkey.translate = NULL; gkey.numeric = gkey.general_numeric = gkey.month = gkey.reverse = 0; gkey.skipsblanks = gkey.skipeblanks = 0; files = (char **) xmalloc (sizeof (char *) * argc); for (i = 1; i < argc; ++i) { if (argv[i][0] == '+') { if (key) insertkey (key); key = (struct keyfield *) xmalloc (sizeof (struct keyfield)); key_init (key); s = argv[i] + 1; if (! (ISDIGIT (*s) || (*s == '.' && ISDIGIT (s[1])))) badfieldspec (argv[i]); for (t = 0; ISDIGIT (*s); ++s) t = 10 * t + *s - '0'; t2 = 0; if (*s == '.') for (++s; ISDIGIT (*s); ++s) t2 = 10 * t2 + *s - '0'; if (t2 || t) { key->sword = t; key->schar = t2; } else key->sword = -1; s = set_ordering (s, key, bl_start); if (*s) badfieldspec (argv[i]); } else if (argv[i][0] == '-' && argv[i][1]) { s = argv[i] + 1; if (ISDIGIT (*s) || (*s == '.' && ISDIGIT (s[1]))) { if (!key) { /* Provoke with `sort -9'. */ error (0, 0, _("when using the old-style +POS and -POS \key specifiers,\nthe +POS specifier must come first")); usage (SORT_FAILURE); } for (t = 0; ISDIGIT (*s); ++s) t = t * 10 + *s - '0'; t2 = 0; if (*s == '.') for (++s; ISDIGIT (*s); ++s) t2 = t2 * 10 + *s - '0'; key->eword = t; key->echar = t2; s = set_ordering (s, key, bl_end); if (*s) badfieldspec (argv[i]); insertkey (key); key = NULL; } else while (*s) { s = set_ordering (s, &gkey, bl_both); switch (*s) { case '\0': break; case 'c': checkonly = 1; break; case 'k': if (s[1]) ++s; else { if (i == argc - 1) error (SORT_FAILURE, 0, _("option `-k' requires an argument")); else s = argv[++i]; } if (key) insertkey (key); key = (struct keyfield *) xmalloc (sizeof (struct keyfield)); key_init (key); /* Get POS1. */ if (!ISDIGIT (*s)) badfieldspec (argv[i]); for (t = 0; ISDIGIT (*s); ++s) t = 10 * t + *s - '0'; if (t == 0) { /* Provoke with `sort -k0' */ error (0, 0, _("the starting field number argument \to the `-k' option must be positive")); badfieldspec (argv[i]); } --t; t2 = 0; if (*s == '.') { if (!ISDIGIT (s[1])) { /* Provoke with `sort -k1.' */ error (0, 0, _("starting field spec has `.' but \lacks following character offset")); badfieldspec (argv[i]); } for (++s; ISDIGIT (*s); ++s) t2 = 10 * t2 + *s - '0'; if (t2 == 0) { /* Provoke with `sort -k1.0' */ error (0, 0, _("starting field character offset \argument to the `-k' option\nmust be positive")); badfieldspec (argv[i]); } --t2; } if (t2 || t) { key->sword = t; key->schar = t2; } else key->sword = -1; s = set_ordering (s, key, bl_start); if (*s == 0) { key->eword = -1; key->echar = 0; } else if (*s != ',') badfieldspec (argv[i]); else if (*s == ',') { /* Skip over comma. */ ++s; if (*s == 0) { /* Provoke with `sort -k1,' */ error (0, 0, _("field specification has `,' but \lacks following field spec")); badfieldspec (argv[i]); } /* Get POS2. */ for (t = 0; ISDIGIT (*s); ++s) t = t * 10 + *s - '0'; if (t == 0) { /* Provoke with `sort -k1,0' */ error (0, 0, _("ending field number argument \to the `-k' option must be positive")); badfieldspec (argv[i]); } --t; t2 = 0; if (*s == '.') { if (!ISDIGIT (s[1])) { /* Provoke with `sort -k1,1.' */ error (0, 0, _("ending field spec has `.' \but lacks following character offset")); badfieldspec (argv[i]); } for (++s; ISDIGIT (*s); ++s) t2 = t2 * 10 + *s - '0'; } else { /* `-k 2,3' is equivalent to `+1 -3'. */ ++t; } key->eword = t; key->echar = t2; s = set_ordering (s, key, bl_end); if (*s) badfieldspec (argv[i]); } insertkey (key); key = NULL; goto outer; case 'm': mergeonly = 1; break; case 'o': if (s[1]) outfile = s + 1; else { if (i == argc - 1) error (SORT_FAILURE, 0, _("option `-o' requires an argument")); else outfile = argv[++i]; } goto outer; case 's': stable = 1; break; case 't': if (s[1]) tab = *++s; else if (i < argc - 1) { tab = *argv[++i]; goto outer; } else error (SORT_FAILURE, 0, _("option `-t' requires an argument")); break; case 'T': if (s[1]) temp_dir = ++s; else { if (i < argc - 1) temp_dir = argv[++i]; else error (SORT_FAILURE, 0, _("option `-T' requires an argument")); } goto outer; /* break; */ case 'u': unique = 1; break; case 'z': eolchar = 0; break; case 'y': /* Accept and ignore e.g. -y0 for compatibility with Solaris 2. */ goto outer; default: fprintf (stderr, _("%s: unrecognized option `-%c'\n"), argv[0], *s); usage (SORT_FAILURE); } if (*s) ++s; } } else /* Not an option. */ { files[nfiles++] = argv[i]; } outer:; } if (key) insertkey (key); /* Inheritance of global options to individual keys. */ for (key = keyhead.next; key; key = key->next) if (!key->ignore && !key->translate && !key->skipsblanks && !key->reverse && !key->skipeblanks && !key->month && !key->numeric && !key->general_numeric) { key->ignore = gkey.ignore; key->translate = gkey.translate; key->skipsblanks = gkey.skipsblanks; key->skipeblanks = gkey.skipeblanks; key->month = gkey.month; key->numeric = gkey.numeric; key->general_numeric = gkey.general_numeric; key->reverse = gkey.reverse; } if (!keyhead.next && (gkey.ignore || gkey.translate || gkey.skipsblanks || gkey.skipeblanks || gkey.month || gkey.numeric || gkey.general_numeric)) insertkey (&gkey); reverse = gkey.reverse; if (nfiles == 0) { nfiles = 1; files = − } if (checkonly) { /* POSIX requires that sort return 1 IFF invoked with -c and the input is not properly sorted. */ exit (check (files, nfiles) == 0 ? 0 : 1); } if (!STREQ (outfile, "-")) { struct stat outstat; if (stat (outfile, &outstat) == 0) { /* The following code prevents a race condition when people use the brain dead shell programming idiom: cat file | sort -o file This feature is provided for historical compatibility, but we strongly discourage ever relying on this in new shell programs. */ /* Temporarily copy each input file that might be another name for the output file. When in doubt (e.g. a pipe), copy. */ for (i = 0; i < nfiles; ++i) { char buf[8192]; FILE *in_fp; FILE *out_fp; int cc; if (S_ISREG (outstat.st_mode) && !STREQ (outfile, files[i])) { struct stat instat; if ((STREQ (files[i], "-") ? fstat (STDIN_FILENO, &instat) : stat (files[i], &instat)) != 0) { error (0, errno, "%s", files[i]); cleanup (); exit (SORT_FAILURE); } if (S_ISREG (instat.st_mode) && !SAME_INODE (instat, outstat)) { /* We know the files are distinct. */ continue; } } in_fp = xfopen (files[i], "r"); tmp = tempname (); out_fp = xtmpfopen (tmp); /* FIXME: maybe use copy.c(copy) here. */ while ((cc = fread (buf, 1, sizeof buf, in_fp)) > 0) write_bytes (buf, cc, out_fp, tmp); if (ferror (in_fp)) { error (0, errno, "%s", files[i]); cleanup (); exit (SORT_FAILURE); } xfclose (out_fp); xfclose (in_fp); files[i] = tmp; } ofp = xfopen (outfile, "w"); } else { /* A non-`-' outfile was specified, but the file doesn't yet exist. Before opening it for writing (thus creating it), make sure all of the input files exist. Otherwise, creating the output file could create an otherwise missing input file, making sort succeed when it should fail. */ for (i = 0; i < nfiles; ++i) { struct stat sb; if (STREQ (files[i], "-")) continue; if (stat (files[i], &sb)) { error (0, errno, "%s", files[i]); cleanup (); exit (SORT_FAILURE); } } ofp = xfopen (outfile, "w"); } } else { ofp = stdout; } if (mergeonly) merge (files, nfiles, ofp, outfile); else sort (files, nfiles, ofp, outfile); cleanup (); /* If we wait for the implicit flush on exit, and the parent process has closed stdout (e.g., exec >&- in a shell), then the output file winds up empty. I don't understand why. This is under SunOS, Solaris, Ultrix, and Irix. This premature fflush makes the output reappear. --karl@cs.umb.edu */ if (fflush (ofp) < 0) error (SORT_FAILURE, errno, _("%s: write error"), outfile); if (have_read_stdin && fclose (stdin) == EOF) error (SORT_FAILURE, errno, "%s", outfile); if (ferror (stdout) || fclose (stdout) == EOF) error (SORT_FAILURE, errno, _("%s: write error"), outfile); exit (EXIT_SUCCESS);}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -