1 /* sort - sort lines of text (with all kinds of options).
2 Copyright (C) 1988, 1991 Free Software Foundation
3
4 This program is free software; you can redistribute it and/or modify
5 it under the terms of the GNU General Public License as published by
6 the Free Software Foundation; either version 2, or (at your option)
7 any later version.
8
9 This program is distributed in the hope that it will be useful,
10 but WITHOUT ANY WARRANTY; without even the implied warranty of
11 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 GNU General Public License for more details.
13
14 You should have received a copy of the GNU General Public License
15 along with this program; if not, write to the Free Software
16 Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
17
18 Written December 1988 by Mike Haertel.
19 The author may be reached (Email) at the address mike@ai.mit.edu,
20 or (US mail) as Mike Haertel c/o Free Software Foundation. */
21
22 #define _GNU_SOURCE
23 #include <ctype.h>
24 #ifndef isblank
25 #define isblank(c) ((c) == ' ' || (c) == '\t')
26 #endif
27 #include <sys/types.h>
28 #include <signal.h>
29 #include <stdio.h>
30 #include <sys/stat.h>
31 #include <unistd.h>
32 #include <string.h>
33 #include <errno.h>
34 #include <stdlib.h>
35 #include <fcntl.h>
36 #include <limits.h>
37
38 static void usage ();
39
40 #define min(a, b) ((a) < (b) ? (a) : (b))
41 #define UCHAR_LIM (UCHAR_MAX + 1)
42 #define UCHAR(c) ((unsigned char) (c))
43
44 #ifdef isascii
45 #define ISALNUM(c) (isascii(c) && isalnum(c))
46 #define ISDIGIT(c) (isascii(c) && isdigit(c))
47 #define ISPRINT(c) (isascii(c) && isprint(c))
48 #define ISLOWER(c) (isascii(c) && islower(c))
49 #else
50 #define ISALNUM(c) isalnum(c)
51 #define ISDIGIT(c) isdigit(c)
52 #define ISPRINT(c) isprint(c)
53 #define ISLOWER(c) islower(c)
54 #endif
55
56 /* The kind of blanks for '-b' to skip in various options. */
57 enum blanktype { bl_start, bl_end, bl_both };
58
59 /* The name this program was run with. */
60 char *program_name;
61
62 /* Table of digits. */
63 static int digits[UCHAR_LIM];
64
65 /* Table of white space. */
66 static int blanks[UCHAR_LIM];
67
68 /* Table of non-printing characters. */
69 static int nonprinting[UCHAR_LIM];
70
71 /* Table of non-dictionary characters (not letters, digits, or blanks). */
72 static int nondictionary[UCHAR_LIM];
73
74 /* Translation table folding lower case to upper. */
75 static char fold_toupper[UCHAR_LIM];
76
77 /* Table mapping 3-letter month names to integers.
78 Alphabetic order allows binary search. */
79 static struct month
80 {
81 char *name;
82 int val;
83 } monthtab[] =
84 {
85 "APR", 4,
86 "AUG", 8,
87 "DEC", 12,
88 "FEB", 2,
89 "JAN", 1,
90 "JUL", 7,
91 "JUN", 6,
92 "MAR", 3,
93 "MAY", 5,
94 "NOV", 11,
95 "OCT", 10,
96 "SEP", 9
97 };
98
99 /* During the merge phase, the number of files to merge at once. */
100 #define NMERGE 16
101
102 /* Initial buffer size for in core sorting. Will not grow unless a
103 line longer than this is seen. */
104 static int sortalloc = 524288;
105
106 /* Initial buffer size for in core merge buffers. Bear in mind that
107 up to NMERGE * mergealloc bytes may be allocated for merge buffers. */
108 static int mergealloc = 16384;
109
110 /* Guess of average line length. */
111 static int linelength = 30;
112
113 /* Maximum number of elements for the array(s) of struct line's, in bytes. */
114 #define LINEALLOC 262144
115
116 /* Prefix for temporary file names. */
117 static char *prefix;
118
119 /* Flag to reverse the order of all comparisons. */
120 static int reverse;
121
122 /* Flag for stable sort. This turns off the last ditch bytewise
123 comparison of lines, and instead leaves lines in the same order
124 they were read if all keys compare equal. */
125 static int stable;
126
127 /* Tab character separating fields. If NUL, then fields are separated
128 by the empty string between a non-whitespace character and a whitespace
129 character. */
130 static char tab;
131
132 /* Flag to remove consecutive duplicate lines from the output.
133 Only the last of a sequence of equal lines will be output. */
134 static int unique;
135
136 /* Nonzero if any of the input files are the standard input. */
137 static int have_read_stdin;
138
139 /* Lines are held in core as counted strings. */
140 struct line
141 {
142 char *text; /* Text of the line. */
143 int length; /* Length not including final newline. */
144 char *keybeg; /* Start of first key. */
145 char *keylim; /* Limit of first key. */
146 };
147
148 /* Arrays of lines. */
149 struct lines
150 {
151 struct line *lines; /* Dynamically allocated array of lines. */
152 int used; /* Number of slots used. */
153 int alloc; /* Number of slots allocated. */
154 int limit; /* Max number of slots to allocate. */
155 };
156
157 /* Input buffers. */
158 struct buffer
159 {
160 char *buf; /* Dynamically allocated buffer. */
161 int used; /* Number of bytes used. */
162 int alloc; /* Number of bytes allocated. */
163 int left; /* Number of bytes left after line parsing. */
164 };
165
166 /* Lists of key field comparisons to be tried. */
167 static struct keyfield
168 {
169 int sword; /* Zero-origin 'word' to start at. */
170 int schar; /* Additional characters to skip. */
171 int skipsblanks; /* Skip leading white space at start. */
172 int eword; /* Zero-origin first word after field. */
173 int echar; /* Additional characters in field. */
174 int skipeblanks; /* Skip trailing white space at finish. */
175 int *ignore; /* Boolean array of characters to ignore. */
176 char *translate; /* Translation applied to characters. */
177 int numeric; /* Flag for numeric comparison. */
178 int month; /* Flag for comparison by month name. */
179 int reverse; /* Reverse the sense of comparison. */
180 struct keyfield *next; /* Next keyfield to try. */
181 } keyhead;
182
183 /* The list of temporary files. */
184 static struct tempnode
185 {
186 char *name;
187 struct tempnode *next;
188 } temphead;
189
190 /* Clean up any remaining temporary files. */
191
192 static void
cleanup()193 cleanup ()
194 {
195 struct tempnode *node;
196
197 for (node = temphead.next; node; node = node->next)
198 unlink (node->name);
199 }
200
201 /* Allocate N bytes of memory dynamically, with error checking. */
202
203 char *
xmalloc(n)204 xmalloc (n)
205 unsigned n;
206 {
207 char *p;
208
209 p = (char *)malloc (n);
210 if (p == 0)
211 {
212 error (0, 0, "virtual memory exhausted");
213 cleanup ();
214 exit (2);
215 }
216 return p;
217 }
218
219 /* Change the size of an allocated block of memory P to N bytes,
220 with error checking.
221 If P is NULL, run xmalloc.
222 If N is 0, run free and return NULL. */
223
224 char *
xrealloc(p,n)225 xrealloc (p, n)
226 char *p;
227 unsigned n;
228 {
229 if (p == 0)
230 return xmalloc (n);
231 if (n == 0)
232 {
233 free (p);
234 return 0;
235 }
236 p = realloc (p, n);
237 if (p == 0)
238 {
239 error (0, 0, "virtual memory exhausted");
240 cleanup ();
241 exit (2);
242 }
243 return p;
244 }
245
246 static FILE *
xfopen(file,how)247 xfopen (file, how)
248 char *file, *how;
249 {
250 FILE *fp = strcmp (file, "-") ? fopen (file, how) : stdin;
251
252 if (fp == 0)
253 {
254 error (0, errno, "%s", file);
255 cleanup ();
256 exit (2);
257 }
258 if (fp == stdin)
259 have_read_stdin = 1;
260 return fp;
261 }
262
263 static void
xfclose(fp)264 xfclose (fp)
265 FILE *fp;
266 {
267 fflush (fp);
268 if (fp != stdin && fp != stdout)
269 {
270 if (fclose (fp) != 0)
271 {
272 error (0, errno, "error closing file");
273 cleanup ();
274 exit (2);
275 }
276 }
277 else
278 /* Allow reading stdin from tty more than once. */
279 clearerr (fp);
280 }
281
282 static void
xfwrite(buf,size,nelem,fp)283 xfwrite (buf, size, nelem, fp)
284 char *buf;
285 int size, nelem;
286 FILE *fp;
287 {
288 if (fwrite (buf, size, nelem, fp) != nelem)
289 {
290 error (0, errno, "write error");
291 cleanup ();
292 exit (2);
293 }
294 }
295
296 /* Return a name for a temporary file. */
297
298 static char *
tempname()299 tempname ()
300 {
301 static int seq;
302 int len = strlen (prefix);
303 char *name = xmalloc (len + 16);
304 struct tempnode *node =
305 (struct tempnode *) xmalloc (sizeof (struct tempnode));
306
307 if (len && prefix[len - 1] != '/')
308 sprintf (name, "%s/sort%5.5d%5.5d", prefix, getpid (), ++seq);
309 else
310 sprintf (name, "%ssort%5.5d%5.5d", prefix, getpid (), ++seq);
311 node->name = name;
312 node->next = temphead.next;
313 temphead.next = node;
314 return name;
315 }
316
317 /* Search through the list of temporary files for NAME;
318 remove it if it is found on the list. */
319
320 static void
zaptemp(name)321 zaptemp (name)
322 char *name;
323 {
324 struct tempnode *node, *temp;
325
326 for (node = &temphead; node->next; node = node->next)
327 if (!strcmp (name, node->next->name))
328 break;
329 if (node->next)
330 {
331 temp = node->next;
332 unlink (temp->name);
333 free (temp->name);
334 node->next = temp->next;
335 free ((char *) temp);
336 }
337 }
338
339 /* Initialize the character class tables. */
340
341 static void
inittables()342 inittables ()
343 {
344 int i;
345
346 for (i = 0; i < UCHAR_LIM; ++i)
347 {
348 if (isblank (i))
349 blanks[i] = 1;
350 if (ISDIGIT (i))
351 digits[i] = 1;
352 if (!ISPRINT (i))
353 nonprinting[i] = 1;
354 if (!ISALNUM (i) && !isblank (i))
355 nondictionary[i] = 1;
356 if (ISLOWER (i))
357 fold_toupper[i] = toupper (i);
358 else
359 fold_toupper[i] = i;
360 }
361 }
362
363 /* Initialize BUF, allocating ALLOC bytes initially. */
364
365 static void
initbuf(buf,alloc)366 initbuf (buf, alloc)
367 struct buffer *buf;
368 int alloc;
369 {
370 buf->alloc = alloc;
371 buf->buf = xmalloc (buf->alloc);
372 buf->used = buf->left = 0;
373 }
374
375 /* Fill BUF reading from FP, moving buf->left bytes from the end
376 of buf->buf to the beginning first. If EOF is reached and the
377 file wasn't terminated by a newline, supply one. Return a count
378 of bytes buffered. */
379
380 static int
fillbuf(buf,fp)381 fillbuf (buf, fp)
382 struct buffer *buf;
383 FILE *fp;
384 {
385 int cc;
386
387 bcopy (buf->buf + buf->used - buf->left, buf->buf, buf->left);
388 buf->used = buf->left;
389
390 while (!feof (fp) && (buf->used == 0 || !memchr (buf->buf, '\n', buf->used)))
391 {
392 if (buf->used == buf->alloc)
393 {
394 buf->alloc *= 2;
395 buf->buf = xrealloc (buf->buf, buf->alloc);
396 }
397 cc = fread (buf->buf + buf->used, 1, buf->alloc - buf->used, fp);
398 if (ferror (fp))
399 {
400 error (0, errno, "read error");
401 cleanup ();
402 exit (2);
403 }
404 buf->used += cc;
405 }
406
407 if (feof (fp) && buf->used && buf->buf[buf->used - 1] != '\n')
408 {
409 if (buf->used == buf->alloc)
410 {
411 buf->alloc *= 2;
412 buf->buf = xrealloc (buf->buf, buf->alloc);
413 }
414 buf->buf[buf->used++] = '\n';
415 }
416
417 return buf->used;
418 }
419
420 /* Initialize LINES, allocating space for ALLOC lines initially.
421 LIMIT is the maximum possible number of lines to allocate space
422 for, ever. */
423
424 static void
initlines(lines,alloc,limit)425 initlines (lines, alloc, limit)
426 struct lines *lines;
427 int alloc;
428 int limit;
429 {
430 lines->alloc = alloc;
431 lines->lines = (struct line *) xmalloc (lines->alloc * sizeof (struct line));
432 lines->used = 0;
433 lines->limit = limit;
434 }
435
436 /* Return a pointer to the first character of the field specified
437 by KEY in LINE. */
438
439 static char *
begfield(line,key)440 begfield (line, key)
441 struct line *line;
442 struct keyfield *key;
443 {
444 register char *ptr = line->text, *lim = ptr + line->length;
445 register int sword = key->sword, schar = key->schar;
446
447 if (tab)
448 while (ptr < lim && sword--)
449 {
450 while (ptr < lim && *ptr != tab)
451 ++ptr;
452 if (ptr < lim)
453 ++ptr;
454 }
455 else
456 while (ptr < lim && sword--)
457 {
458 while (ptr < lim && blanks[UCHAR (*ptr)])
459 ++ptr;
460 while (ptr < lim && !blanks[UCHAR (*ptr)])
461 ++ptr;
462 }
463
464 if (key->skipsblanks)
465 while (ptr < lim && blanks[UCHAR (*ptr)])
466 ++ptr;
467
468 while (ptr < lim && schar--)
469 ++ptr;
470
471 return ptr;
472 }
473
474 /* Return the limit of (a pointer to the first character after) the field
475 in LINE specified by KEY. */
476
477 static char *
limfield(line,key)478 limfield (line, key)
479 struct line *line;
480 struct keyfield *key;
481 {
482 register char *ptr = line->text, *lim = ptr + line->length;
483 register int eword = key->eword, echar = key->echar;
484
485 if (tab)
486 while (ptr < lim && eword--)
487 {
488 while (ptr < lim && *ptr != tab)
489 ++ptr;
490 if (ptr < lim && (eword || key->skipeblanks))
491 ++ptr;
492 }
493 else
494 while (ptr < lim && eword--)
495 {
496 while (ptr < lim && blanks[UCHAR (*ptr)])
497 ++ptr;
498 while (ptr < lim && !blanks[UCHAR (*ptr)])
499 ++ptr;
500 }
501
502 if (key->skipeblanks)
503 while (ptr < lim && blanks[UCHAR (*ptr)])
504 ++ptr;
505
506 while (ptr < lim && echar--)
507 ++ptr;
508
509 return ptr;
510 }
511
512 /* Find the lines in BUF, storing pointers and lengths in LINES.
513 Also replace newlines with NULs. */
514
515 static void
findlines(buf,lines)516 findlines (buf, lines)
517 struct buffer *buf;
518 struct lines *lines;
519 {
520 register char *beg = buf->buf, *lim = buf->buf + buf->used, *ptr;
521 struct keyfield *key = keyhead.next;
522
523 lines->used = 0;
524
525 while (beg < lim && (ptr = memchr (beg, '\n', lim - beg))
526 && lines->used < lines->limit)
527 {
528 /* There are various places in the code that rely on a NUL
529 being at the end of in-core lines; NULs inside the lines
530 will not cause trouble, though. */
531 *ptr = '\0';
532
533 if (lines->used == lines->alloc)
534 {
535 lines->alloc *= 2;
536 lines->lines = (struct line *)
537 xrealloc ((char *) lines->lines,
538 lines->alloc * sizeof (struct line));
539 }
540
541 lines->lines[lines->used].text = beg;
542 lines->lines[lines->used].length = ptr - beg;
543
544 /* Precompute the position of the first key for efficiency. */
545 if (key)
546 {
547 if (key->eword >= 0)
548 lines->lines[lines->used].keylim =
549 limfield (&lines->lines[lines->used], key);
550 else
551 lines->lines[lines->used].keylim = ptr;
552
553 if (key->sword >= 0)
554 lines->lines[lines->used].keybeg =
555 begfield (&lines->lines[lines->used], key);
556 else
557 {
558 if (key->skipsblanks)
559 while (blanks[UCHAR (*beg)])
560 ++beg;
561 lines->lines[lines->used].keybeg = beg;
562 }
563 }
564
565 ++lines->used;
566 beg = ptr + 1;
567 }
568
569 buf->left = lim - beg;
570 }
571
572 /* Compare strings A and B containing decimal fractions < 1. Each string
573 should begin with a decimal point followed immediately by the digits
574 of the fraction. Strings not of this form are considered to be zero. */
575
576 static int
fraccompare(a,b)577 fraccompare (a, b)
578 register char *a, *b;
579 {
580 register tmpa = UCHAR (*a), tmpb = UCHAR (*b);
581
582 if (tmpa == '.' && tmpb == '.')
583 {
584 do
585 tmpa = UCHAR (*++a), tmpb = UCHAR (*++b);
586 while (tmpa == tmpb && digits[tmpa]);
587 if (digits[tmpa] && digits[tmpb])
588 return tmpa - tmpb;
589 if (digits[tmpa])
590 {
591 while (tmpa == '0')
592 tmpa = UCHAR (*++a);
593 if (digits[tmpa])
594 return 1;
595 return 0;
596 }
597 if (digits[tmpb])
598 {
599 while (tmpb == '0')
600 tmpb = UCHAR (*++b);
601 if (digits[tmpb])
602 return -1;
603 return 0;
604 }
605 return 0;
606 }
607 else if (tmpa == '.')
608 {
609 do
610 tmpa = UCHAR (*++a);
611 while (tmpa == '0');
612 if (digits[tmpa])
613 return 1;
614 return 0;
615 }
616 else if (tmpb == '.')
617 {
618 do
619 tmpb = UCHAR (*++b);
620 while (tmpb == '0');
621 if (digits[tmpb])
622 return -1;
623 return 0;
624 }
625 return 0;
626 }
627
628 /* Compare strings A and B as numbers without explicitly converting them to
629 machine numbers. Comparatively slow for short strings, but asymptotically
630 hideously fast. */
631
632 static int
numcompare(a,b)633 numcompare (a, b)
634 register char *a, *b;
635 {
636 register int tmpa, tmpb, loga, logb, tmp;
637
638 tmpa = UCHAR (*a), tmpb = UCHAR (*b);
639
640 if (tmpa == '-')
641 {
642 tmpa = UCHAR (*++a);
643 if (tmpb != '-')
644 {
645 if (digits[tmpa] && digits[tmpb])
646 return -1;
647 return 0;
648 }
649 tmpb = UCHAR (*++b);
650
651 while (tmpa == '0')
652 tmpa = UCHAR (*++a);
653 while (tmpb == '0')
654 tmpb = UCHAR (*++b);
655
656 while (tmpa == tmpb && digits[tmpa])
657 tmpa = UCHAR (*++a), tmpb = UCHAR (*++b);
658
659 if ((tmpa == '.' && !digits[tmpb]) || (tmpb == '.' && !digits[tmpa]))
660 return -fraccompare (a, b);
661
662 if (digits[tmpa])
663 for (loga = 1; digits[UCHAR (*++a)]; ++loga)
664 ;
665 else
666 loga = 0;
667
668 if (digits[tmpb])
669 for (logb = 1; digits[UCHAR (*++b)]; ++logb)
670 ;
671 else
672 logb = 0;
673
674 if (tmp = logb - loga)
675 return tmp;
676
677 if (!loga)
678 return 0;
679
680 return tmpb - tmpa;
681 }
682 else if (tmpb == '-')
683 {
684 if (digits[UCHAR (tmpa)] && digits[UCHAR (*++b)])
685 return 1;
686 return 0;
687 }
688 else
689 {
690 while (tmpa == '0')
691 tmpa = UCHAR (*++a);
692 while (tmpb == '0')
693 tmpb = UCHAR (*++b);
694
695 while (tmpa == tmpb && digits[tmpa])
696 tmpa = UCHAR (*++a), tmpb = UCHAR (*++b);
697
698 if ((tmpa == '.' && !digits[tmpb]) || (tmpb == '.' && !digits[tmpa]))
699 return fraccompare (a, b);
700
701 if (digits[tmpa])
702 for (loga = 1; digits[UCHAR (*++a)]; ++loga)
703 ;
704 else
705 loga = 0;
706
707 if (digits[tmpb])
708 for (logb = 1; digits[UCHAR (*++b)]; ++logb)
709 ;
710 else
711 logb = 0;
712
713 if (tmp = loga - logb)
714 return tmp;
715
716 if (!loga)
717 return 0;
718
719 return tmpa - tmpb;
720 }
721 }
722
723 /* Return an integer <= 12 associated with month name S with length LEN,
724 0 if the name in S is not recognized. */
725
726 static int
getmonth(s,len)727 getmonth (s, len)
728 char *s;
729 int len;
730 {
731 char month[4];
732 register int i, lo = 0, hi = 12;
733
734 if (len < 3)
735 return 0;
736
737 for (i = 0; i < 3; ++i)
738 month[i] = fold_toupper[UCHAR (s[i])];
739 month[3] = '\0';
740
741 while (hi - lo > 1)
742 if (strcmp (month, monthtab[(lo + hi) / 2].name) < 0)
743 hi = (lo + hi) / 2;
744 else
745 lo = (lo + hi) / 2;
746 if (!strcmp (month, monthtab[lo].name))
747 return monthtab[lo].val;
748 return 0;
749 }
750
751 /* Compare two lines A and B trying every key in sequence until there
752 are no more keys or a difference is found. */
753
754 static int
keycompare(a,b)755 keycompare (a, b)
756 struct line *a, *b;
757 {
758 register char *texta, *textb, *lima, *limb, *translate;
759 register int *ignore;
760 struct keyfield *key;
761 int diff = 0, iter = 0, lena, lenb;
762
763 for (key = keyhead.next; key; key = key->next, ++iter)
764 {
765 ignore = key->ignore;
766 translate = key->translate;
767
768 /* Find the beginning and limit of each field. */
769 if (iter || a->keybeg == NULL || b->keybeg == NULL)
770 {
771 if (key->eword >= 0)
772 lima = limfield (a, key), limb = limfield (b, key);
773 else
774 lima = a->text + a->length, limb = b->text + b->length;
775
776 if (key->sword >= 0)
777 texta = begfield (a, key), textb = begfield (b, key);
778 else
779 {
780 texta = a->text, textb = b->text;
781 if (key->skipsblanks)
782 {
783 while (texta < lima && blanks[UCHAR (*texta)])
784 ++texta;
785 while (textb < limb && blanks[UCHAR (*textb)])
786 ++textb;
787 }
788 }
789 }
790 else
791 {
792 /* For the first iteration only, the key positions have
793 been precomputed for us. */
794 texta = a->keybeg, lima = a->keylim;
795 textb = b->keybeg, limb = b->keylim;
796 }
797
798 /* Find the lengths. */
799 lena = lima - texta, lenb = limb - textb;
800 if (lena < 0)
801 lena = 0;
802 if (lenb < 0)
803 lenb = 0;
804
805 /* Actually compare the fields. */
806 if (key->numeric)
807 {
808 if (*lima || *limb)
809 {
810 char savea = *lima, saveb = *limb;
811
812 *lima = *limb = '\0';
813 diff = numcompare (texta, textb);
814 *lima = savea, *limb = saveb;
815 }
816 else
817 diff = numcompare (texta, textb);
818
819 if (diff)
820 return key->reverse ? -diff : diff;
821 continue;
822 }
823 else if (key->month)
824 {
825 diff = getmonth (texta, lena) - getmonth (textb, lenb);
826 if (diff)
827 return key->reverse ? -diff : diff;
828 continue;
829 }
830 else if (ignore && translate)
831 while (texta < lima && textb < limb)
832 {
833 while (texta < lima && ignore[UCHAR (*texta)])
834 ++texta;
835 while (textb < limb && ignore[UCHAR (*textb)])
836 ++textb;
837 if (texta < lima && textb < limb &&
838 translate[UCHAR (*texta++)] != translate[UCHAR (*textb++)])
839 {
840 diff = translate[UCHAR (*--texta)] - translate[UCHAR (*--textb)];
841 break;
842 }
843 }
844 else if (ignore)
845 while (texta < lima && textb < limb)
846 {
847 while (texta < lima && ignore[UCHAR (*texta)])
848 ++texta;
849 while (textb < limb && ignore[UCHAR (*textb)])
850 ++textb;
851 if (texta < lima && textb < limb && *texta++ != *textb++)
852 {
853 diff = *--texta - *--textb;
854 break;
855 }
856 }
857 else if (translate)
858 while (texta < lima && textb < limb)
859 {
860 if (translate[UCHAR (*texta++)] != translate[UCHAR (*textb++)])
861 {
862 diff = translate[UCHAR (*--texta)] - translate[UCHAR (*--textb)];
863 break;
864 }
865 }
866 else
867 diff = memcmp (texta, textb, min (lena, lenb));
868
869 if (diff)
870 return key->reverse ? -diff : diff;
871 if (diff = lena - lenb)
872 return key->reverse ? -diff : diff;
873 }
874
875 return 0;
876 }
877
878 /* Compare two lines A and B, returning negative, zero, or positive
879 depending on whether A compares less than, equal to, or greater than B. */
880
881 static int
compare(a,b)882 compare (a, b)
883 register struct line *a, *b;
884 {
885 int diff, tmpa, tmpb, mini;
886
887 if (keyhead.next)
888 {
889 diff = keycompare (a, b);
890 if (diff)
891 return diff;
892 if (!unique && !stable)
893 {
894 tmpa = a->length, tmpb = b->length;
895 diff = memcmp (a->text, b->text, min (tmpa, tmpb));
896 if (!diff)
897 diff = tmpa - tmpb;
898 }
899 }
900 else
901 {
902 tmpa = a->length, tmpb = b->length;
903 mini = min (tmpa, tmpb);
904 if (mini == 0)
905 diff = tmpa - tmpb;
906 else
907 {
908 char *ap = a->text, *bp = b->text;
909
910 diff = *ap - *bp;
911 if (diff == 0)
912 {
913 diff = memcmp (ap, bp, mini);
914 if (diff == 0)
915 diff = tmpa - tmpb;
916 }
917 }
918 }
919
920 return reverse ? -diff : diff;
921 }
922
923 /* Check that the lines read from the given FP come in order. Return
924 1 if they do and 0 if there is a disorder. */
925
926 static int
checkfp(fp)927 checkfp (fp)
928 FILE *fp;
929 {
930 struct buffer buf; /* Input buffer. */
931 struct lines lines; /* Lines scanned from the buffer. */
932 struct line temp; /* Copy of previous line. */
933 int cc; /* Character count. */
934 int cmp; /* Result of calling compare. */
935 int alloc, i, success = 1;
936
937 initbuf (&buf, mergealloc);
938 initlines (&lines, mergealloc / linelength + 1,
939 LINEALLOC / ((NMERGE + NMERGE) * sizeof (struct line)));
940 alloc = linelength;
941 temp.text = xmalloc (alloc);
942
943 cc = fillbuf (&buf, fp);
944 findlines (&buf, &lines);
945
946 if (cc)
947 do
948 {
949 /* Compare each line in the buffer with its successor. */
950 for (i = 0; i < lines.used - 1; ++i)
951 {
952 cmp = compare (&lines.lines[i], &lines.lines[i + 1]);
953 if ((unique && cmp >= 0) || (cmp > 0))
954 {
955 success = 0;
956 goto finish;
957 }
958 }
959
960 /* Save the last line of the buffer and refill the buffer. */
961 if (lines.lines[lines.used - 1].length > alloc)
962 {
963 while (lines.lines[lines.used - 1].length + 1 > alloc)
964 alloc *= 2;
965 temp.text = xrealloc (temp.text, alloc);
966 }
967 bcopy (lines.lines[lines.used - 1].text, temp.text,
968 lines.lines[lines.used - 1].length + 1);
969 temp.length = lines.lines[lines.used - 1].length;
970
971 cc = fillbuf (&buf, fp);
972 if (cc)
973 {
974 findlines (&buf, &lines);
975 /* Make sure the line saved from the old buffer contents is
976 less than or equal to the first line of the new buffer. */
977 cmp = compare (&temp, &lines.lines[0]);
978 if ((unique && cmp >= 0) || (cmp > 0))
979 {
980 success = 0;
981 break;
982 }
983 }
984 }
985 while (cc);
986
987 finish:
988 xfclose (fp);
989 free (buf.buf);
990 free ((char *) lines.lines);
991 free (temp.text);
992 return success;
993 }
994
995 /* Merge lines from FPS onto OFP. NFPS cannot be greater than NMERGE.
996 Close FPS before returning. */
997
998 static void
mergefps(fps,nfps,ofp)999 mergefps (fps, nfps, ofp)
1000 FILE *fps[], *ofp;
1001 register int nfps;
1002 {
1003 struct buffer buffer[NMERGE]; /* Input buffers for each file. */
1004 struct lines lines[NMERGE]; /* Line tables for each buffer. */
1005 struct line saved; /* Saved line for unique check. */
1006 int savedflag = 0; /* True if there is a saved line. */
1007 int savealloc; /* Size allocated for the saved line. */
1008 int cur[NMERGE]; /* Current line in each line table. */
1009 int ord[NMERGE]; /* Table representing a permutation of fps,
1010 such that lines[ord[0]].lines[cur[ord[0]]]
1011 is the smallest line and will be next
1012 output. */
1013 register int i, j, t;
1014
1015 /* Allocate space for a saved line if necessary. */
1016 if (unique)
1017 {
1018 savealloc = linelength;
1019 saved.text = xmalloc (savealloc);
1020 }
1021
1022 /* Read initial lines from each input file. */
1023 for (i = 0; i < nfps; ++i)
1024 {
1025 initbuf (&buffer[i], mergealloc);
1026 /* If a file is empty, eliminate it from future consideration. */
1027 while (i < nfps && !fillbuf (&buffer[i], fps[i]))
1028 {
1029 xfclose (fps[i]);
1030 --nfps;
1031 for (j = i; j < nfps; ++j)
1032 fps[j] = fps[j + 1];
1033 }
1034 if (i == nfps)
1035 free (buffer[i].buf);
1036 else
1037 {
1038 initlines (&lines[i], mergealloc / linelength + 1,
1039 LINEALLOC / ((NMERGE + NMERGE) * sizeof (struct line)));
1040 findlines (&buffer[i], &lines[i]);
1041 cur[i] = 0;
1042 }
1043 }
1044
1045 /* Set up the ord table according to comparisons among input lines.
1046 Since this only reorders two items if one is strictly greater than
1047 the other, it is stable. */
1048 for (i = 0; i < nfps; ++i)
1049 ord[i] = i;
1050 for (i = 1; i < nfps; ++i)
1051 if (compare (&lines[ord[i - 1]].lines[cur[ord[i - 1]]],
1052 &lines[ord[i]].lines[cur[ord[i]]]) > 0)
1053 t = ord[i - 1], ord[i - 1] = ord[i], ord[i] = t, i = 0;
1054
1055 /* Repeatedly output the smallest line until no input remains. */
1056 while (nfps)
1057 {
1058 /* If uniqified output is turned out, output only the first of
1059 an identical series of lines. */
1060 if (unique)
1061 {
1062 if (savedflag && compare (&saved, &lines[ord[0]].lines[cur[ord[0]]]))
1063 {
1064 xfwrite (saved.text, 1, saved.length, ofp);
1065 putc ('\n', ofp);
1066 savedflag = 0;
1067 }
1068 if (!savedflag)
1069 {
1070 if (savealloc < lines[ord[0]].lines[cur[ord[0]]].length + 1)
1071 {
1072 while (savealloc < lines[ord[0]].lines[cur[ord[0]]].length + 1)
1073 savealloc *= 2;
1074 saved.text = xrealloc (saved.text, savealloc);
1075 }
1076 saved.length = lines[ord[0]].lines[cur[ord[0]]].length;
1077 bcopy (lines[ord[0]].lines[cur[ord[0]]].text, saved.text,
1078 saved.length + 1);
1079 savedflag = 1;
1080 }
1081 }
1082 else
1083 {
1084 xfwrite (lines[ord[0]].lines[cur[ord[0]]].text, 1,
1085 lines[ord[0]].lines[cur[ord[0]]].length, ofp);
1086 putc ('\n', ofp);
1087 }
1088
1089 /* Check if we need to read more lines into core. */
1090 if (++cur[ord[0]] == lines[ord[0]].used)
1091 if (fillbuf (&buffer[ord[0]], fps[ord[0]]))
1092 {
1093 findlines (&buffer[ord[0]], &lines[ord[0]]);
1094 cur[ord[0]] = 0;
1095 }
1096 else
1097 {
1098 /* We reached EOF on fps[ord[0]]. */
1099 for (i = 1; i < nfps; ++i)
1100 if (ord[i] > ord[0])
1101 --ord[i];
1102 --nfps;
1103 xfclose (fps[ord[0]]);
1104 free (buffer[ord[0]].buf);
1105 free ((char *) lines[ord[0]].lines);
1106 for (i = ord[0]; i < nfps; ++i)
1107 {
1108 fps[i] = fps[i + 1];
1109 buffer[i] = buffer[i + 1];
1110 lines[i] = lines[i + 1];
1111 cur[i] = cur[i + 1];
1112 }
1113 for (i = 0; i < nfps; ++i)
1114 ord[i] = ord[i + 1];
1115 continue;
1116 }
1117
1118 /* The new line just read in may be larger than other lines
1119 already in core; push it back in the queue until we encounter
1120 a line larger than it. */
1121 for (i = 1; i < nfps; ++i)
1122 {
1123 t = compare (&lines[ord[0]].lines[cur[ord[0]]],
1124 &lines[ord[i]].lines[cur[ord[i]]]);
1125 if (!t)
1126 t = ord[0] - ord[i];
1127 if (t < 0)
1128 break;
1129 }
1130 t = ord[0];
1131 for (j = 1; j < i; ++j)
1132 ord[j - 1] = ord[j];
1133 ord[i - 1] = t;
1134 }
1135
1136 if (unique && savedflag)
1137 {
1138 xfwrite (saved.text, 1, saved.length, ofp);
1139 putc ('\n', ofp);
1140 free (saved.text);
1141 }
1142 }
1143
1144 /* Sort the array LINES with NLINES members, using TEMP for temporary space. */
1145
1146 static void
sortlines(lines,nlines,temp)1147 sortlines (lines, nlines, temp)
1148 struct line *lines, *temp;
1149 int nlines;
1150 {
1151 register struct line *lo, *hi, *t;
1152 register int nlo, nhi;
1153
1154 if (nlines == 2)
1155 {
1156 if (compare (&lines[0], &lines[1]) > 0)
1157 *temp = lines[0], lines[0] = lines[1], lines[1] = *temp;
1158 return;
1159 }
1160
1161 nlo = nlines / 2;
1162 lo = lines;
1163 nhi = nlines - nlo;
1164 hi = lines + nlo;
1165
1166 if (nlo > 1)
1167 sortlines (lo, nlo, temp);
1168
1169 if (nhi > 1)
1170 sortlines (hi, nhi, temp);
1171
1172 t = temp;
1173
1174 while (nlo && nhi)
1175 if (compare (lo, hi) <= 0)
1176 *t++ = *lo++, --nlo;
1177 else
1178 *t++ = *hi++, --nhi;
1179 while (nlo--)
1180 *t++ = *lo++;
1181
1182 for (lo = lines, nlo = nlines - nhi, t = temp; nlo; --nlo)
1183 *lo++ = *t++;
1184 }
1185
1186 /* Check that each of the NFILES FILES is ordered.
1187 Return a count of disordered files. */
1188
1189 static int
check(files,nfiles)1190 check (files, nfiles)
1191 char *files[];
1192 int nfiles;
1193 {
1194 int i, disorders = 0;
1195 FILE *fp;
1196
1197 for (i = 0; i < nfiles; ++i)
1198 {
1199 fp = xfopen (files[i], "r");
1200 if (!checkfp (fp))
1201 {
1202 printf ("%s: disorder on %s\n", program_name, files[i]);
1203 ++disorders;
1204 }
1205 }
1206 return disorders;
1207 }
1208
1209 /* Merge NFILES FILES onto OFP. */
1210
1211 static void
merge(files,nfiles,ofp)1212 merge (files, nfiles, ofp)
1213 char *files[];
1214 int nfiles;
1215 FILE *ofp;
1216 {
1217 int i, j, t;
1218 char *temp;
1219 FILE *fps[NMERGE], *tfp;
1220
1221 while (nfiles > NMERGE)
1222 {
1223 t = 0;
1224 for (i = 0; i < nfiles / NMERGE; ++i)
1225 {
1226 for (j = 0; j < NMERGE; ++j)
1227 fps[j] = xfopen (files[i * NMERGE + j], "r");
1228 tfp = xfopen (temp = tempname (), "w");
1229 mergefps (fps, NMERGE, tfp);
1230 xfclose (tfp);
1231 for (j = 0; j < NMERGE; ++j)
1232 zaptemp (files[i * NMERGE + j]);
1233 files[t++] = temp;
1234 }
1235 for (j = 0; j < nfiles % NMERGE; ++j)
1236 fps[j] = xfopen (files[i * NMERGE + j], "r");
1237 tfp = xfopen (temp = tempname (), "w");
1238 mergefps (fps, nfiles % NMERGE, tfp);
1239 xfclose (tfp);
1240 for (j = 0; j < nfiles % NMERGE; ++j)
1241 zaptemp (files[i * NMERGE + j]);
1242 files[t++] = temp;
1243 nfiles = t;
1244 }
1245
1246 for (i = 0; i < nfiles; ++i)
1247 fps[i] = xfopen (files[i], "r");
1248 mergefps (fps, i, ofp);
1249 for (i = 0; i < nfiles; ++i)
1250 zaptemp (files[i]);
1251 }
1252
1253 /* Sort NFILES FILES onto OFP. */
1254
1255 static void
sort(files,nfiles,ofp)1256 sort (files, nfiles, ofp)
1257 char **files;
1258 int nfiles;
1259 FILE *ofp;
1260 {
1261 struct buffer buf;
1262 struct lines lines;
1263 struct line *tmp;
1264 int i, ntmp;
1265 FILE *fp, *tfp;
1266 struct tempnode *node;
1267 int ntemp = 0;
1268 char **tempfiles;
1269
1270 initbuf (&buf, sortalloc);
1271 initlines (&lines, sortalloc / linelength + 1,
1272 LINEALLOC / sizeof (struct line));
1273 ntmp = lines.alloc;
1274 tmp = (struct line *) xmalloc (ntmp * sizeof (struct line));
1275
1276 while (nfiles--)
1277 {
1278 fp = xfopen (*files++, "r");
1279 while (fillbuf (&buf, fp))
1280 {
1281 findlines (&buf, &lines);
1282 if (lines.used > ntmp)
1283 {
1284 while (lines.used > ntmp)
1285 ntmp *= 2;
1286 tmp = (struct line *)
1287 xrealloc ((char *) tmp, ntmp * sizeof (struct line));
1288 }
1289 sortlines (lines.lines, lines.used, tmp);
1290 if (feof (fp) && !nfiles && !ntemp && !buf.left)
1291 tfp = ofp;
1292 else
1293 {
1294 ++ntemp;
1295 tfp = xfopen (tempname (), "w");
1296 }
1297 for (i = 0; i < lines.used; ++i)
1298 if (!unique || i == 0
1299 || compare (&lines.lines[i], &lines.lines[i - 1]))
1300 {
1301 xfwrite (lines.lines[i].text, 1, lines.lines[i].length, tfp);
1302 putc ('\n', tfp);
1303 }
1304 if (tfp != ofp)
1305 xfclose (tfp);
1306 }
1307 xfclose (fp);
1308 }
1309
1310 free (buf.buf);
1311 free ((char *) lines.lines);
1312 free ((char *) tmp);
1313
1314 if (ntemp)
1315 {
1316 tempfiles = (char **) xmalloc (ntemp * sizeof (char *));
1317 i = ntemp;
1318 for (node = temphead.next; node; node = node->next)
1319 tempfiles[--i] = node->name;
1320 merge (tempfiles, ntemp, ofp);
1321 free ((char *) tempfiles);
1322 }
1323 }
1324
1325 /* Insert key KEY at the end of the list (`keyhead'). */
1326
1327 static void
insertkey(key)1328 insertkey (key)
1329 struct keyfield *key;
1330 {
1331 struct keyfield *k = &keyhead;
1332
1333 while (k->next)
1334 k = k->next;
1335 k->next = key;
1336 key->next = NULL;
1337 }
1338
1339 static void
badfieldspec(s)1340 badfieldspec (s)
1341 char *s;
1342 {
1343 error (2, 0, "invalid field specification `%s'", s);
1344 }
1345
1346 /* Handle interrupts and hangups. */
1347
1348 static void
sighandler(sig)1349 sighandler (sig)
1350 int sig;
1351 {
1352 struct sigaction sigact;
1353
1354 sigact.sa_handler = SIG_DFL;
1355 sigemptyset (&sigact.sa_mask);
1356 sigact.sa_flags = 0;
1357 sigaction (sig, &sigact, NULL);
1358 cleanup ();
1359 kill (getpid (), sig);
1360 }
1361
1362 /* Set the ordering options for KEY specified in S.
1363 Return the address of the first character in S that
1364 is not a valid ordering option.
1365 BLANKTYPE is the kind of blanks that 'b' should skip. */
1366
1367 static char *
set_ordering(s,key,blanktype)1368 set_ordering (s, key, blanktype)
1369 register char *s;
1370 struct keyfield *key;
1371 enum blanktype blanktype;
1372 {
1373 while (*s)
1374 {
1375 switch (*s)
1376 {
1377 case 'b':
1378 if (blanktype == bl_start || blanktype == bl_both)
1379 key->skipsblanks = 1;
1380 if (blanktype == bl_end || blanktype == bl_both)
1381 key->skipeblanks = 1;
1382 break;
1383 case 'd':
1384 key->ignore = nondictionary;
1385 break;
1386 case 'f':
1387 key->translate = fold_toupper;
1388 break;
1389 #if 0
1390 case 'g':
1391 /* Reserved for comparing floating-point numbers. */
1392 break;
1393 #endif
1394 case 'i':
1395 key->ignore = nonprinting;
1396 break;
1397 case 'M':
1398 key->skipsblanks = key->skipeblanks = key->month = 1;
1399 break;
1400 case 'n':
1401 key->skipsblanks = key->skipeblanks = key->numeric = 1;
1402 break;
1403 case 'r':
1404 key->reverse = 1;
1405 break;
1406 default:
1407 return s;
1408 }
1409 ++s;
1410 }
1411 return s;
1412 }
1413
1414 void
main(argc,argv)1415 main (argc, argv)
1416 int argc;
1417 char *argv[];
1418 {
1419 struct keyfield *key = NULL, gkey;
1420 char *s;
1421 int i, t, t2;
1422 int checkonly = 0, mergeonly = 0, nfiles = 0;
1423 char *minus = "-", *outfile = minus, **files, *tmp;
1424 FILE *ofp;
1425 struct sigaction oldact, newact;
1426
1427 program_name = argv[0];
1428 have_read_stdin = 0;
1429 inittables ();
1430
1431 prefix = getenv ("TMPDIR");
1432 if (prefix == NULL)
1433 prefix = "/tmp";
1434
1435 newact.sa_handler = sighandler;
1436 sigemptyset (&newact.sa_mask);
1437 newact.sa_flags = 0;
1438
1439 sigaction (SIGINT, NULL, &oldact);
1440 if (oldact.sa_handler != SIG_IGN)
1441 sigaction (SIGINT, &newact, NULL);
1442 sigaction (SIGHUP, NULL, &oldact);
1443 if (oldact.sa_handler != SIG_IGN)
1444 sigaction (SIGHUP, &newact, NULL);
1445
1446 gkey.sword = gkey.eword = -1;
1447 gkey.ignore = NULL;
1448 gkey.translate = NULL;
1449 gkey.numeric = gkey.month = gkey.reverse = 0;
1450 gkey.skipsblanks = gkey.skipeblanks = 0;
1451
1452 files = (char **) xmalloc (sizeof (char *) * argc);
1453
1454 for (i = 1; i < argc; ++i)
1455 {
1456 if (argv[i][0] == '+')
1457 {
1458 if (key)
1459 insertkey (key);
1460 key = (struct keyfield *) xmalloc (sizeof (struct keyfield));
1461 key->eword = -1;
1462 key->ignore = NULL;
1463 key->translate = NULL;
1464 key->skipsblanks = key->skipeblanks = 0;
1465 key->numeric = key->month = key->reverse = 0;
1466 s = argv[i] + 1;
1467 if (!digits[UCHAR (*s)])
1468 badfieldspec (argv[i]);
1469 for (t = 0; digits[UCHAR (*s)]; ++s)
1470 t = 10 * t + *s - '0';
1471 t2 = 0;
1472 if (*s == '.')
1473 for (++s; digits[UCHAR (*s)]; ++s)
1474 t2 = 10 * t2 + *s - '0';
1475 if (t2 || t)
1476 {
1477 key->sword = t;
1478 key->schar = t2;
1479 }
1480 else
1481 key->sword = -1;
1482 s = set_ordering (s, key, bl_start);
1483 if (*s)
1484 badfieldspec (argv[i]);
1485 }
1486 else if (argv[i][0] == '-')
1487 {
1488 if (!strcmp ("-", argv[i]))
1489 break;
1490 s = argv[i] + 1;
1491 if (digits[UCHAR (*s)])
1492 {
1493 if (!key)
1494 usage ();
1495 for (t = 0; digits[UCHAR (*s)]; ++s)
1496 t = t * 10 + *s - '0';
1497 t2 = 0;
1498 if (*s == '.')
1499 for (++s; digits[UCHAR (*s)]; ++s)
1500 t2 = t2 * 10 + *s - '0';
1501 key->eword = t;
1502 key->echar = t2;
1503 s = set_ordering (s, key, bl_end);
1504 if (*s)
1505 badfieldspec (argv[i]);
1506 insertkey (key);
1507 key = NULL;
1508 }
1509 else
1510 while (*s)
1511 {
1512 s = set_ordering (s, &gkey, bl_both);
1513 switch (*s)
1514 {
1515 case '\0':
1516 break;
1517 case 'c':
1518 checkonly = 1;
1519 break;
1520 case 'k':
1521 if (s[1])
1522 ++s;
1523 else
1524 {
1525 if (i == argc - 1)
1526 error (2, 0, "option `-k' requires an argument");
1527 else
1528 s = argv[++i];
1529 }
1530 if (key)
1531 insertkey (key);
1532 key = (struct keyfield *)
1533 xmalloc (sizeof (struct keyfield));
1534 key->eword = -1;
1535 key->ignore = NULL;
1536 key->translate = NULL;
1537 key->skipsblanks = key->skipeblanks = 0;
1538 key->numeric = key->month = key->reverse = 0;
1539 /* Get POS1. */
1540 if (!digits[UCHAR (*s)])
1541 badfieldspec (argv[i]);
1542 for (t = 0; digits[UCHAR (*s)]; ++s)
1543 t = 10 * t + *s - '0';
1544 if (t)
1545 t--;
1546 t2 = 0;
1547 if (*s == '.')
1548 {
1549 for (++s; digits[UCHAR (*s)]; ++s)
1550 t2 = 10 * t2 + *s - '0';
1551 if (t2)
1552 t2--;
1553 }
1554 if (t2 || t)
1555 {
1556 key->sword = t;
1557 key->schar = t2;
1558 }
1559 else
1560 key->sword = -1;
1561 s = set_ordering (s, key, bl_start);
1562 if (*s && *s != ',')
1563 badfieldspec (argv[i]);
1564 else if (*s++)
1565 {
1566 /* Get POS2. */
1567 for (t = 0; digits[UCHAR (*s)]; ++s)
1568 t = t * 10 + *s - '0';
1569 t2 = 0;
1570 if (*s == '.')
1571 {
1572 for (++s; digits[UCHAR (*s)]; ++s)
1573 t2 = t2 * 10 + *s - '0';
1574 if (t2)
1575 t--;
1576 }
1577 key->eword = t;
1578 key->echar = t2;
1579 s = set_ordering (s, key, bl_end);
1580 if (*s)
1581 badfieldspec (argv[i]);
1582 }
1583 insertkey (key);
1584 key = NULL;
1585 goto outer;
1586 case 'm':
1587 mergeonly = 1;
1588 break;
1589 case 'o':
1590 if (s[1])
1591 outfile = s + 1;
1592 else
1593 {
1594 if (i == argc - 1)
1595 error (2, 0, "option `-o' requires an argument");
1596 else
1597 outfile = argv[++i];
1598 }
1599 goto outer;
1600 case 's':
1601 stable = 1;
1602 break;
1603 case 't':
1604 if (s[1])
1605 tab = *++s;
1606 else if (i < argc - 1)
1607 {
1608 tab = *argv[++i];
1609 goto outer;
1610 }
1611 else
1612 error (2, 0, "option `-t' requires an argument");
1613 break;
1614 case 'u':
1615 unique = 1;
1616 break;
1617 default:
1618 fprintf (stderr, "%s: unrecognized option `-%c'\n",
1619 argv[0], *s);
1620 usage ();
1621 }
1622 if (*s)
1623 ++s;
1624 }
1625 }
1626 else /* Not an option. */
1627 {
1628 files[nfiles++] = argv[i];
1629 }
1630 outer:;
1631 }
1632
1633 if (key)
1634 insertkey (key);
1635
1636 /* Inheritance of global options to individual keys. */
1637 for (key = keyhead.next; key; key = key->next)
1638 if (!key->ignore && !key->translate && !key->skipsblanks && !key->reverse
1639 && !key->skipeblanks && !key->month && !key->numeric)
1640 {
1641 key->ignore = gkey.ignore;
1642 key->translate = gkey.translate;
1643 key->skipsblanks = gkey.skipsblanks;
1644 key->skipeblanks = gkey.skipeblanks;
1645 key->month = gkey.month;
1646 key->numeric = gkey.numeric;
1647 key->reverse = gkey.reverse;
1648 }
1649
1650 if (!keyhead.next && (gkey.ignore || gkey.translate || gkey.skipsblanks
1651 || gkey.reverse || gkey.skipeblanks
1652 || gkey.month || gkey.numeric))
1653 insertkey (&gkey);
1654
1655 if (nfiles == 0)
1656 {
1657 nfiles = 1;
1658 files = −
1659 }
1660
1661 if (checkonly)
1662 exit (check (files, nfiles) != 0);
1663
1664 if (strcmp (outfile, "-"))
1665 {
1666 for (i = 0; i < nfiles; ++i)
1667 if (!strcmp (outfile, files[i]))
1668 break;
1669 if (i == nfiles)
1670 ofp = xfopen (outfile, "w");
1671 else
1672 {
1673 char buf[8192];
1674 FILE *fp = xfopen (outfile, "r");
1675 int cc;
1676
1677 tmp = tempname ();
1678 ofp = xfopen (tmp, "w");
1679 while ((cc = fread (buf, 1, sizeof buf, fp)) > 0)
1680 xfwrite (buf, 1, cc, ofp);
1681 if (ferror (fp))
1682 {
1683 error (0, errno, "%s", outfile);
1684 cleanup ();
1685 exit (2);
1686 }
1687 xfclose (ofp);
1688 xfclose (fp);
1689 files[i] = tmp;
1690 ofp = xfopen (outfile, "w");
1691 }
1692 }
1693 else
1694 ofp = stdout;
1695
1696 if (mergeonly)
1697 merge (files, nfiles, ofp);
1698 else
1699 sort (files, nfiles, ofp);
1700 cleanup ();
1701
1702 if (have_read_stdin && fclose (stdin) == EOF)
1703 error (1, errno, "-");
1704 if (ferror (stdout) || fclose (stdout) == EOF)
1705 error (1, 0, "write error");
1706
1707 exit (0);
1708 }
1709
1710 static void
usage()1711 usage ()
1712 {
1713 fprintf (stderr, "\
1714 Usage: %s [-cmus] [-t separator] [-o output-file] [-bdfiMnr] [+POS1 [-POS2]]\n\
1715 [-k POS1[,POS2]] [file...]\n",
1716 program_name);
1717 exit (2);
1718 }
1719
error(n,e,s,s1)1720 error(n,e, s,s1) {
1721 if(e) fprintf(stderr,"error %d:", e);
1722 fprintf(stderr,s, s1);
1723 if(n) exit(n);
1724 }
1725