blob: 1edc7d1caa4f3dcc510abb628601388e7a799099 [file] [log] [blame]
Erik Andersene49d5ec2000-02-08 19:58:47 +00001/* vi: set sw=4 ts=4: */
John Beppuc0ca4731999-12-21 20:00:35 +00002/*
John Beppu568cb7b1999-12-22 23:02:12 +00003 * Mini sort implementation for busybox
John Beppuc0ca4731999-12-21 20:00:35 +00004 *
5 *
Erik Andersen61677fe2000-04-13 01:18:56 +00006 * Copyright (C) 1999,2000 by Lineo, inc.
John Beppuc0ca4731999-12-21 20:00:35 +00007 * Written by John Beppu <beppu@lineo.com>
8 *
9 * This program is free software; you can redistribute it and/or modify
10 * it under the terms of the GNU General Public License as published by
11 * the Free Software Foundation; either version 2 of the License, or
12 * (at your option) any later version.
13 *
14 * This program is distributed in the hope that it will be useful,
15 * but WITHOUT ANY WARRANTY; without even the implied warranty of
16 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
17 * General Public License for more details.
18 *
19 * You should have received a copy of the GNU General Public License
20 * along with this program; if not, write to the Free Software
21 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
22 *
23 */
24
25#include "internal.h"
26#include <sys/types.h>
27#include <fcntl.h>
28#include <dirent.h>
29#include <stdio.h>
30#include <errno.h>
31
Erik Andersen029011b2000-03-04 21:19:32 +000032static const char sort_usage[] = "sort [-n]"
33#ifdef BB_FEATURE_SORT_REVERSE
34" [-r]"
35#endif
Erik Andersen7ab9c7e2000-05-12 19:41:47 +000036" [FILE]...\n"
37#ifndef BB_FEATURE_TRIVIAL_HELP
38"\nSorts lines of text in the specified files\n"
39#endif
40;
Erik Andersen029011b2000-03-04 21:19:32 +000041
42#ifdef BB_FEATURE_SORT_REVERSE
43#define APPLY_REVERSE(x) (reverse ? -(x) : (x))
44static int reverse = 0;
45#else
46#define APPLY_REVERSE(x) (x)
47#endif
John Beppuc0ca4731999-12-21 20:00:35 +000048
John Beppuf3e59041999-12-22 22:24:52 +000049/* typedefs _______________________________________________________________ */
John Beppuc0ca4731999-12-21 20:00:35 +000050
51/* line node */
John Beppuf3e59041999-12-22 22:24:52 +000052typedef struct Line {
Erik Andersene49d5ec2000-02-08 19:58:47 +000053 char *data; /* line data */
54 struct Line *next; /* pointer to next line node */
John Beppuc0ca4731999-12-21 20:00:35 +000055} Line;
56
57/* singly-linked list of lines */
58typedef struct {
Erik Andersene49d5ec2000-02-08 19:58:47 +000059 int len; /* number of Lines */
60 Line **sorted; /* array fed to qsort */
Erik Andersene49d5ec2000-02-08 19:58:47 +000061 Line *head; /* head of List */
62 Line *current; /* current Line */
John Beppuc0ca4731999-12-21 20:00:35 +000063} List;
64
John Beppuf3e59041999-12-22 22:24:52 +000065/* comparison function */
Erik Andersene49d5ec2000-02-08 19:58:47 +000066typedef int (Compare) (const void *, const void *);
John Beppuf3e59041999-12-22 22:24:52 +000067
John Beppuc0ca4731999-12-21 20:00:35 +000068
John Beppu38efa791999-12-22 00:30:29 +000069/* methods ________________________________________________________________ */
John Beppuc0ca4731999-12-21 20:00:35 +000070
71static const int max = 1024;
72
John Beppu38efa791999-12-22 00:30:29 +000073/* mallocate Line */
Erik Andersene49d5ec2000-02-08 19:58:47 +000074static Line *line_alloc()
John Beppuc0ca4731999-12-21 20:00:35 +000075{
Erik Andersene49d5ec2000-02-08 19:58:47 +000076 Line *self;
Erik Andersene49d5ec2000-02-08 19:58:47 +000077 self = malloc(1 * sizeof(Line));
78 return self;
John Beppu38efa791999-12-22 00:30:29 +000079}
80
John Beppu38efa791999-12-22 00:30:29 +000081/* Construct Line from FILE* */
Erik Andersene49d5ec2000-02-08 19:58:47 +000082static Line *line_newFromFile(FILE * src)
John Beppu38efa791999-12-22 00:30:29 +000083{
Erik Andersene49d5ec2000-02-08 19:58:47 +000084 Line *self;
John Beppu5a728cf2000-04-17 04:22:09 +000085 char *cstring = NULL;
John Beppu38efa791999-12-22 00:30:29 +000086
John Beppu5a728cf2000-04-17 04:22:09 +000087 if ((cstring = cstring_lineFromFile(src))) {
Erik Andersene49d5ec2000-02-08 19:58:47 +000088 self = line_alloc();
89 if (self == NULL) {
90 return NULL;
91 }
John Beppu5a728cf2000-04-17 04:22:09 +000092 self->data = cstring;
93 self->next = NULL;
Erik Andersene49d5ec2000-02-08 19:58:47 +000094 return self;
95 }
96 return NULL;
John Beppuc0ca4731999-12-21 20:00:35 +000097}
98
John Beppu019513a1999-12-22 17:57:31 +000099/* Line destructor */
Erik Andersene49d5ec2000-02-08 19:58:47 +0000100static Line *line_release(Line * self)
John Beppu019513a1999-12-22 17:57:31 +0000101{
Erik Andersene49d5ec2000-02-08 19:58:47 +0000102 if (self->data) {
103 free(self->data);
104 free(self);
105 }
106 return self;
John Beppu019513a1999-12-22 17:57:31 +0000107}
108
John Beppuc0ca4731999-12-21 20:00:35 +0000109
110/* Comparison */
111
John Beppu568cb7b1999-12-22 23:02:12 +0000112/* ascii order */
Erik Andersene49d5ec2000-02-08 19:58:47 +0000113static int compare_ascii(const void *a, const void *b)
John Beppuf3e59041999-12-22 22:24:52 +0000114{
Erik Andersene49d5ec2000-02-08 19:58:47 +0000115 Line **doh;
116 Line *x, *y;
John Beppu568cb7b1999-12-22 23:02:12 +0000117
Erik Andersene49d5ec2000-02-08 19:58:47 +0000118 doh = (Line **) a;
119 x = *doh;
120 doh = (Line **) b;
121 y = *doh;
John Beppu568cb7b1999-12-22 23:02:12 +0000122
Erik Andersene49d5ec2000-02-08 19:58:47 +0000123 // fprintf(stdout, "> %p: %s< %p: %s", x, x->data, y, y->data);
Erik Andersen029011b2000-03-04 21:19:32 +0000124 return APPLY_REVERSE(strcmp(x->data, y->data));
John Beppuf3e59041999-12-22 22:24:52 +0000125}
John Beppuc0ca4731999-12-21 20:00:35 +0000126
John Beppu568cb7b1999-12-22 23:02:12 +0000127/* numeric order */
Erik Andersene49d5ec2000-02-08 19:58:47 +0000128static int compare_numeric(const void *a, const void *b)
John Beppuf3e59041999-12-22 22:24:52 +0000129{
Erik Andersene49d5ec2000-02-08 19:58:47 +0000130 Line **doh;
131 Line *x, *y;
132 int xint, yint;
John Beppuee512a31999-12-23 00:02:49 +0000133
Erik Andersene49d5ec2000-02-08 19:58:47 +0000134 doh = (Line **) a;
135 x = *doh;
136 doh = (Line **) b;
137 y = *doh;
John Beppuee512a31999-12-23 00:02:49 +0000138
Erik Andersene49d5ec2000-02-08 19:58:47 +0000139 xint = strtoul(x->data, NULL, 10);
140 yint = strtoul(y->data, NULL, 10);
John Beppuee512a31999-12-23 00:02:49 +0000141
Erik Andersen029011b2000-03-04 21:19:32 +0000142 return APPLY_REVERSE(xint - yint);
John Beppuf3e59041999-12-22 22:24:52 +0000143}
John Beppuc0ca4731999-12-21 20:00:35 +0000144
145
146/* List */
147
John Beppu38efa791999-12-22 00:30:29 +0000148/* */
Erik Andersene49d5ec2000-02-08 19:58:47 +0000149static List *list_init(List * self)
John Beppu38efa791999-12-22 00:30:29 +0000150{
Erik Andersene49d5ec2000-02-08 19:58:47 +0000151 self->len = 0;
152 self->sorted = NULL;
153 self->head = NULL;
154 self->current = NULL;
155 return self;
John Beppu38efa791999-12-22 00:30:29 +0000156}
John Beppuc0ca4731999-12-21 20:00:35 +0000157
John Beppu38efa791999-12-22 00:30:29 +0000158/* for simplicity, the List gains ownership of the line */
Erik Andersene49d5ec2000-02-08 19:58:47 +0000159static List *list_insert(List * self, Line * line)
John Beppu38efa791999-12-22 00:30:29 +0000160{
Erik Andersene49d5ec2000-02-08 19:58:47 +0000161 if (line == NULL) {
162 return NULL;
163 }
John Beppuc0ca4731999-12-21 20:00:35 +0000164
Erik Andersene49d5ec2000-02-08 19:58:47 +0000165 /* first insertion */
166 if (self->head == NULL) {
167 self->head = line;
168 self->current = line;
John Beppuc0ca4731999-12-21 20:00:35 +0000169
John Beppu5a728cf2000-04-17 04:22:09 +0000170 /* all subsequent insertions */
Erik Andersene49d5ec2000-02-08 19:58:47 +0000171 } else {
172 self->current->next = line;
173 self->current = line;
174 }
175 self->len++;
176 return self;
John Beppu38efa791999-12-22 00:30:29 +0000177}
178
John Beppuf3e59041999-12-22 22:24:52 +0000179/* order the list according to compare() */
Erik Andersene49d5ec2000-02-08 19:58:47 +0000180static List *list_sort(List * self, Compare * compare)
John Beppuf3e59041999-12-22 22:24:52 +0000181{
Erik Andersene49d5ec2000-02-08 19:58:47 +0000182 int i;
183 Line *line;
John Beppuf3e59041999-12-22 22:24:52 +0000184
Erik Andersene49d5ec2000-02-08 19:58:47 +0000185 /* mallocate array of Line*s */
186 self->sorted = (Line **) malloc(self->len * sizeof(Line *));
187 if (self->sorted == NULL) {
188 return NULL;
189 }
John Beppuf3e59041999-12-22 22:24:52 +0000190
Erik Andersene49d5ec2000-02-08 19:58:47 +0000191 /* fill array w/ List's contents */
192 i = 0;
193 line = self->head;
194 while (line) {
195 self->sorted[i++] = line;
196 line = line->next;
197 }
John Beppuf3e59041999-12-22 22:24:52 +0000198
Erik Andersene49d5ec2000-02-08 19:58:47 +0000199 /* apply qsort */
200 qsort(self->sorted, self->len, sizeof(Line *), compare);
201 return self;
John Beppuf3e59041999-12-22 22:24:52 +0000202}
John Beppu38efa791999-12-22 00:30:29 +0000203
204/* precondition: list must be sorted */
Erik Andersene49d5ec2000-02-08 19:58:47 +0000205static List *list_writeToFile(List * self, FILE * dst)
John Beppu38efa791999-12-22 00:30:29 +0000206{
Erik Andersene49d5ec2000-02-08 19:58:47 +0000207 int i;
208 Line **line = self->sorted;
John Beppuf3e59041999-12-22 22:24:52 +0000209
Erik Andersene49d5ec2000-02-08 19:58:47 +0000210 if (self->sorted == NULL) {
211 return NULL;
212 }
213 for (i = 0; i < self->len; i++) {
214 fprintf(dst, "%s", line[i]->data);
215 }
216 return self;
John Beppu38efa791999-12-22 00:30:29 +0000217}
218
219/* deallocate */
Erik Andersene49d5ec2000-02-08 19:58:47 +0000220static void list_release(List * self)
John Beppu38efa791999-12-22 00:30:29 +0000221{
Erik Andersene49d5ec2000-02-08 19:58:47 +0000222 Line *i;
223 Line *die;
John Beppu019513a1999-12-22 17:57:31 +0000224
Erik Andersene49d5ec2000-02-08 19:58:47 +0000225 i = self->head;
226 while (i) {
227 die = i;
228 i = die->next;
229 line_release(die);
230 }
John Beppu38efa791999-12-22 00:30:29 +0000231}
John Beppuc0ca4731999-12-21 20:00:35 +0000232
233
John Beppuc0ca4731999-12-21 20:00:35 +0000234
Erik Andersene49d5ec2000-02-08 19:58:47 +0000235int sort_main(int argc, char **argv)
John Beppuc0ca4731999-12-21 20:00:35 +0000236{
Erik Andersene49d5ec2000-02-08 19:58:47 +0000237 int i;
238 char opt;
239 List list;
240 Line *l;
241 Compare *compare;
John Beppuc0ca4731999-12-21 20:00:35 +0000242
Erik Andersene49d5ec2000-02-08 19:58:47 +0000243 /* init */
244 compare = compare_ascii;
245 list_init(&list);
John Beppuc0ca4731999-12-21 20:00:35 +0000246
Erik Andersene49d5ec2000-02-08 19:58:47 +0000247 /* parse argv[] */
248 for (i = 1; i < argc; i++) {
249 if (argv[i][0] == '-') {
250 opt = argv[i][1];
251 switch (opt) {
Erik Andersene49d5ec2000-02-08 19:58:47 +0000252 case 'h':
253 usage(sort_usage);
254 break;
255 case 'n':
Erik Andersen029011b2000-03-04 21:19:32 +0000256 /* numeric comparison */
Erik Andersene49d5ec2000-02-08 19:58:47 +0000257 compare = compare_numeric;
258 break;
Erik Andersen029011b2000-03-04 21:19:32 +0000259#ifdef BB_FEATURE_SORT_REVERSE
Erik Andersene49d5ec2000-02-08 19:58:47 +0000260 case 'r':
261 /* reverse */
Erik Andersen029011b2000-03-04 21:19:32 +0000262 reverse = 1;
Erik Andersene49d5ec2000-02-08 19:58:47 +0000263 break;
Erik Andersen029011b2000-03-04 21:19:32 +0000264#endif
Erik Andersene49d5ec2000-02-08 19:58:47 +0000265 default:
266 fprintf(stderr, "sort: invalid option -- %c\n", opt);
267 usage(sort_usage);
268 }
269 } else {
270 break;
271 }
272 }
273
274 /* this could be factored better */
275
276 /* work w/ stdin */
277 if (i >= argc) {
278 while ((l = line_newFromFile(stdin))) {
279 list_insert(&list, l);
280 }
281 list_sort(&list, compare);
282 list_writeToFile(&list, stdout);
283 list_release(&list);
284
285 /* work w/ what's left in argv[] */
John Beppuc0ca4731999-12-21 20:00:35 +0000286 } else {
Erik Andersene49d5ec2000-02-08 19:58:47 +0000287 FILE *src;
288
289 for (; i < argc; i++) {
290 src = fopen(argv[i], "r");
291 if (src == NULL) {
292 break;
293 }
294 while ((l = line_newFromFile(src))) {
295 list_insert(&list, l);
296 }
297 fclose(src);
298 }
299 list_sort(&list, compare);
300 list_writeToFile(&list, stdout);
301 list_release(&list);
John Beppuc0ca4731999-12-21 20:00:35 +0000302 }
John Beppuc0ca4731999-12-21 20:00:35 +0000303
Erik Andersene49d5ec2000-02-08 19:58:47 +0000304 exit(0);
John Beppuc0ca4731999-12-21 20:00:35 +0000305}
306
Erik Andersen7ab9c7e2000-05-12 19:41:47 +0000307/* $Id: sort.c,v 1.16 2000/05/12 19:41:47 erik Exp $ */