160911Sbostic /*-
2*62247Sbostic * Copyright (c) 1993
3*62247Sbostic * The Regents of the University of California. All rights reserved.
460911Sbostic *
560911Sbostic * This code is derived from software contributed to Berkeley by
660911Sbostic * Peter McIlroy.
760911Sbostic *
860911Sbostic * %sccs.include.redist.c%
960911Sbostic */
1060911Sbostic
1160911Sbostic #ifndef lint
12*62247Sbostic static char copyright[] =
13*62247Sbostic "@(#) Copyright (c) 1993\n\
14*62247Sbostic The Regents of the University of California. All rights reserved.\n";
1560911Sbostic #endif /* not lint */
1660911Sbostic
1760911Sbostic #ifndef lint
18*62247Sbostic static char sccsid[] = "@(#)sort.c 8.1 (Berkeley) 06/06/93";
1960911Sbostic #endif /* not lint */
2060911Sbostic
2160911Sbostic /* Sort sorts a file using an optional user-defined key.
2260911Sbostic * Sort uses radix sort for internal sorting, and allows
2360911Sbostic * a choice of merge sort and radix sort for external sorting.
2460911Sbostic */
2560911Sbostic
2660911Sbostic #include "sort.h"
2760911Sbostic #include "fsort.h"
2860911Sbostic #include "pathnames.h"
2960911Sbostic
3060911Sbostic #include <paths.h>
3160911Sbostic #include <signal.h>
3260911Sbostic #include <stdlib.h>
3360911Sbostic #include <string.h>
3460911Sbostic #include <unistd.h>
3560911Sbostic
3660911Sbostic int REC_D = '\n';
3760911Sbostic u_char d_mask[NBINS]; /* flags for rec_d, field_d, <blank> */
3860911Sbostic /*
3960911Sbostic * weight tables. Gweights is one of ascii, Rascii..
4060911Sbostic * modified to weight rec_d = 0 (or 255)
4160911Sbostic */
4260911Sbostic extern u_char gweights[NBINS];
4360911Sbostic u_char ascii[NBINS], Rascii[NBINS], RFtable[NBINS], Ftable[NBINS];
4460911Sbostic /*
4560911Sbostic * masks of ignored characters. Alltable is 256 ones
4660911Sbostic */
4760911Sbostic u_char dtable[NBINS], itable[NBINS], alltable[NBINS];
4860911Sbostic int SINGL_FLD = 0, SEP_FLAG = 0, UNIQUE = 0;
4960911Sbostic struct coldesc clist[(ND+1)*2];
5060911Sbostic int ncols = 0;
5160911Sbostic extern struct coldesc clist[(ND+1)*2];
5260911Sbostic extern int ncols;
5360911Sbostic
5460911Sbostic char devstdin[] = _PATH_STDIN;
5560911Sbostic char toutpath[_POSIX_PATH_MAX];
5660911Sbostic
5760911Sbostic static void cleanup __P((void));
5860911Sbostic static void onsig __P((int));
5960911Sbostic static void usage __P((char *));
6060911Sbostic
6160911Sbostic int
main(argc,argv)6260911Sbostic main(argc, argv)
6360911Sbostic int argc;
6460911Sbostic char *argv[];
6560911Sbostic {
6660911Sbostic extern int optind;
6760911Sbostic extern char *optarg;
6860911Sbostic int (*get)();
6960911Sbostic int ch, i, stdinflag = 0, tmp = 0;
7060911Sbostic char cflag = 0, mflag = 0, nflag = 0;
7160911Sbostic char *outfile, *outpath = 0;
7260911Sbostic struct field fldtab[ND+2], *ftpos;
7360911Sbostic union f_handle filelist;
7460911Sbostic FILE *outfd;
7560911Sbostic memset(fldtab, 0, (ND+2)*sizeof(struct field));
7660911Sbostic memset(d_mask, 0, NBINS);
7760911Sbostic d_mask[REC_D = '\n'] = REC_D_F;
7860911Sbostic SINGL_FLD = SEP_FLAG = 0;
7960911Sbostic d_mask['\t'] = d_mask[' '] = BLANK | FLD_D;
8060911Sbostic ftpos = fldtab;
8160911Sbostic fixit(&argc, argv);
8260911Sbostic while ((ch = getopt(argc, argv, "bcdfik:mHno:rt:T:ux")) != EOF) {
8360911Sbostic switch (ch) {
8460911Sbostic case 'b': fldtab->flags |= BI | BT;
8560911Sbostic break;
8660911Sbostic case 'd':
8760911Sbostic case 'i':
8860911Sbostic case 'f':
8960911Sbostic case 'r': tmp |= optval(ch, 0);
9060911Sbostic if (tmp & R && tmp & F)
9160911Sbostic fldtab->weights = RFtable;
9260911Sbostic else if (tmp & F)
9360911Sbostic fldtab->weights = Ftable;
9460911Sbostic else if(tmp & R)
9560911Sbostic fldtab->weights = Rascii;
9660911Sbostic fldtab->flags |= tmp;
9760911Sbostic break;
9860911Sbostic case 'o':
9960911Sbostic outpath = optarg;
10060911Sbostic break;
10160911Sbostic case 'n':
10260911Sbostic nflag = 1;
10360911Sbostic setfield("1n", ++ftpos, fldtab->flags&(~R));
10460911Sbostic break;
10560911Sbostic case 'k':
10660911Sbostic setfield(optarg, ++ftpos, fldtab->flags);
10760911Sbostic break;
10860911Sbostic case 't':
10960911Sbostic if (SEP_FLAG)
11060911Sbostic usage("multiple field delimiters");
11160911Sbostic SEP_FLAG = 1;
11260911Sbostic d_mask[' '] &= ~FLD_D;
11360911Sbostic d_mask['\t'] &= ~FLD_D;
11460911Sbostic d_mask[*optarg] |= FLD_D;
11560911Sbostic if (d_mask[*optarg] & REC_D_F)
11660911Sbostic err(2, "record/field delimiter clash");
11760911Sbostic break;
11860911Sbostic case 'T':
11960911Sbostic if (REC_D != '\n')
12060911Sbostic usage("multiple record delimiters");
12160911Sbostic if ('\n' == (REC_D = *optarg))
12260911Sbostic break;
12360911Sbostic d_mask['\n'] = d_mask[' '];
12460911Sbostic d_mask[REC_D] = REC_D_F;
12560911Sbostic break;
12660911Sbostic case 'u':
12760911Sbostic UNIQUE = 1;
12860911Sbostic break;
12960911Sbostic case 'c':
13060911Sbostic cflag = 1;
13160911Sbostic break;
13260911Sbostic case 'm':
13360911Sbostic mflag = 1;
13460911Sbostic break;
13560911Sbostic case 'H':
13660911Sbostic PANIC = 0;
13760911Sbostic break;
13860911Sbostic case '?':
13960911Sbostic default: usage("");
14060911Sbostic }
14160911Sbostic }
14260911Sbostic if (cflag && argc > optind+1)
14360911Sbostic errx(2, "too many input files for -c option");
14460911Sbostic if (argc - 2 > optind && !strcmp(argv[argc-2], "-o")) {
14560911Sbostic outpath = argv[argc-1];
14660911Sbostic argc -= 2;
14760911Sbostic }
14860911Sbostic if (mflag && argc - optind > (MAXFCT - (16+1))*16)
14960911Sbostic errx(2, "too many input files for -m option");
15060911Sbostic for (i = optind; i < argc; i++) {
15160911Sbostic /* allow one occurrence of /dev/stdin */
15260911Sbostic if (!strcmp(argv[i], "-") || !strcmp(argv[i], devstdin)) {
15360911Sbostic if (stdinflag)
15460911Sbostic warnx("ignoring extra \"%s\" in file list",
15560911Sbostic argv[i]);
15660911Sbostic else {
15760911Sbostic stdinflag = 1;
15860911Sbostic argv[i] = devstdin;
15960911Sbostic }
16060911Sbostic } else if (ch = access(argv[i], R_OK))
16160911Sbostic err(2, "%s", argv[i]);
16260911Sbostic }
16360911Sbostic if (!(fldtab->flags & (I|D) || fldtab[1].icol.num)) {
16460911Sbostic SINGL_FLD = 1;
16560911Sbostic fldtab[0].icol.num = 1;
16660911Sbostic } else {
16760911Sbostic if (!fldtab[1].icol.num) {
16860911Sbostic fldtab[0].flags &= ~(BI|BT);
16960911Sbostic setfield("1", ++ftpos, fldtab->flags);
17060911Sbostic }
17160911Sbostic if (nflag)
17260911Sbostic fldtab[1].flags |= fldtab->flags;
17360911Sbostic fldreset(fldtab);
17460911Sbostic fldtab[0].flags &= ~F;
17560911Sbostic }
17660911Sbostic settables(fldtab[0].flags);
17760911Sbostic num_init();
17860911Sbostic fldtab->weights = gweights;
17960911Sbostic if (optind == argc)
18060911Sbostic argv[--optind] = devstdin;
18160911Sbostic filelist.names = argv+optind;
18260911Sbostic if (SINGL_FLD)
18360911Sbostic get = makeline;
18460911Sbostic else
18560911Sbostic get = makekey;
18660911Sbostic if (cflag) {
18760911Sbostic order(filelist, get, fldtab);
18860911Sbostic /* NOT REACHED */
18960911Sbostic }
19060911Sbostic if (!outpath) {
19160911Sbostic (void)snprintf(toutpath,
19260911Sbostic sizeof(toutpath), "%sstdout", _PATH_DEV);
19360911Sbostic outfile = outpath = toutpath;
19460911Sbostic } else if (!(ch = access(outpath, 0)) &&
19560911Sbostic strncmp(_PATH_DEV, outpath, 5)) {
19660911Sbostic struct sigaction act = {0, SIG_BLOCK, 6};
19760911Sbostic int sigtable[] = {SIGHUP, SIGINT, SIGPIPE, SIGXCPU, SIGXFSZ,
19860911Sbostic SIGVTALRM, SIGPROF, 0};
19960911Sbostic errno = 0;
20060911Sbostic if (access(outpath, W_OK))
20160911Sbostic err(2, "%s", outpath);
20260911Sbostic act.sa_handler = cleanup;
20360911Sbostic (void)snprintf(toutpath, sizeof(toutpath), "%sXXXX", outpath);
20460911Sbostic outfile = mktemp(toutpath);
20560911Sbostic if (!outfile)
20660911Sbostic err(2, "%s", toutpath);
20760911Sbostic (void)atexit(cleanup);
20860911Sbostic for (i = 0; sigtable[i]; ++i) /* always unlink toutpath */
20960911Sbostic sigaction(sigtable[i], &act, 0);
21060911Sbostic } else outfile = outpath;
21160911Sbostic if (!(outfd = fopen(outfile, "w")))
21260911Sbostic err(2, "%s", outfile);
21360911Sbostic if (mflag)
21460911Sbostic fmerge(-1, filelist, argc-optind, get, outfd, putline, fldtab);
21560911Sbostic else
21660911Sbostic fsort(-1, 0, filelist, argc-optind, outfd, fldtab);
21760911Sbostic if (outfile != outpath) {
21860911Sbostic if (access(outfile, 0))
21960911Sbostic err(2, "%s", outfile);
22060911Sbostic (void)unlink(outpath);
22160911Sbostic if (link(outfile, outpath))
22260911Sbostic err(2, "cannot link %s: output left in %s",
22360911Sbostic outpath, outfile);
22460911Sbostic (void)unlink(outfile);
22560911Sbostic }
22660911Sbostic exit(0);
22760911Sbostic }
22860911Sbostic
22960911Sbostic static void
onsig(s)23060911Sbostic onsig(s)
23160911Sbostic int s;
23260911Sbostic {
23360911Sbostic cleanup();
23460911Sbostic exit(2); /* return 2 on error/interrupt */
23560911Sbostic }
23660911Sbostic
23760911Sbostic static void
cleanup()23860911Sbostic cleanup()
23960911Sbostic {
24060911Sbostic if (toutpath[0])
24160911Sbostic (void)unlink(toutpath);
24260911Sbostic }
24360911Sbostic
24460911Sbostic static void
usage(msg)24560911Sbostic usage(msg)
24660911Sbostic char *msg;
24760911Sbostic {
24860911Sbostic if (msg)
24960911Sbostic (void)fprintf(stderr, "sort: %s\n", msg);
25060911Sbostic (void)fprintf(stderr, "usage: [-o output] [-cmubdfinr] [-t char] ");
25160911Sbostic (void)fprintf(stderr, "[-T char] [-k keydef] ... [files]\n");
25260911Sbostic exit(2);
25360911Sbostic }
254