blob: 4301f4303db6e63d06db40389cbc274e23e9a3f0 [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 Andersen5e1189e2000-04-15 16:34:54 +000036" [FILE]...\n\nSorts lines of text in the specified files\n";
Erik Andersen029011b2000-03-04 21:19:32 +000037
38#ifdef BB_FEATURE_SORT_REVERSE
39#define APPLY_REVERSE(x) (reverse ? -(x) : (x))
40static int reverse = 0;
41#else
42#define APPLY_REVERSE(x) (x)
43#endif
John Beppuc0ca4731999-12-21 20:00:35 +000044
John Beppuf3e59041999-12-22 22:24:52 +000045/* typedefs _______________________________________________________________ */
John Beppuc0ca4731999-12-21 20:00:35 +000046
47/* line node */
John Beppuf3e59041999-12-22 22:24:52 +000048typedef struct Line {
Erik Andersene49d5ec2000-02-08 19:58:47 +000049 char *data; /* line data */
50 struct Line *next; /* pointer to next line node */
John Beppuc0ca4731999-12-21 20:00:35 +000051} Line;
52
53/* singly-linked list of lines */
54typedef struct {
Erik Andersene49d5ec2000-02-08 19:58:47 +000055 int len; /* number of Lines */
56 Line **sorted; /* array fed to qsort */
John Beppu38efa791999-12-22 00:30:29 +000057
Erik Andersene49d5ec2000-02-08 19:58:47 +000058 Line *head; /* head of List */
59 Line *current; /* current Line */
John Beppuc0ca4731999-12-21 20:00:35 +000060} List;
61
John Beppuf3e59041999-12-22 22:24:52 +000062/* comparison function */
Erik Andersene49d5ec2000-02-08 19:58:47 +000063typedef int (Compare) (const void *, const void *);
John Beppuf3e59041999-12-22 22:24:52 +000064
John Beppuc0ca4731999-12-21 20:00:35 +000065
John Beppu38efa791999-12-22 00:30:29 +000066/* methods ________________________________________________________________ */
John Beppuc0ca4731999-12-21 20:00:35 +000067
68static const int max = 1024;
69
John Beppu38efa791999-12-22 00:30:29 +000070/* mallocate Line */
Erik Andersene49d5ec2000-02-08 19:58:47 +000071static Line *line_alloc()
John Beppuc0ca4731999-12-21 20:00:35 +000072{
Erik Andersene49d5ec2000-02-08 19:58:47 +000073 Line *self;
74
75 self = malloc(1 * sizeof(Line));
76 return self;
John Beppu38efa791999-12-22 00:30:29 +000077}
78
79/* Initialize Line with string */
Erik Andersene49d5ec2000-02-08 19:58:47 +000080static Line *line_init(Line * self, const char *string)
John Beppu38efa791999-12-22 00:30:29 +000081{
Erik Andersene49d5ec2000-02-08 19:58:47 +000082 self->data = malloc((strlen(string) + 1) * sizeof(char));
83
84 if (self->data == NULL) {
85 return NULL;
86 }
87 strcpy(self->data, string);
88 self->next = NULL;
89 return self;
John Beppu38efa791999-12-22 00:30:29 +000090}
91
92/* Construct Line from FILE* */
Erik Andersene49d5ec2000-02-08 19:58:47 +000093static Line *line_newFromFile(FILE * src)
John Beppu38efa791999-12-22 00:30:29 +000094{
Erik Andersene49d5ec2000-02-08 19:58:47 +000095 char buffer[max];
96 Line *self;
John Beppu38efa791999-12-22 00:30:29 +000097
Erik Andersene49d5ec2000-02-08 19:58:47 +000098 if (fgets(buffer, max, src)) {
99 self = line_alloc();
100 if (self == NULL) {
101 return NULL;
102 }
103 line_init(self, buffer);
104 return self;
105 }
106 return NULL;
John Beppuc0ca4731999-12-21 20:00:35 +0000107}
108
John Beppu019513a1999-12-22 17:57:31 +0000109/* Line destructor */
Erik Andersene49d5ec2000-02-08 19:58:47 +0000110static Line *line_release(Line * self)
John Beppu019513a1999-12-22 17:57:31 +0000111{
Erik Andersene49d5ec2000-02-08 19:58:47 +0000112 if (self->data) {
113 free(self->data);
114 free(self);
115 }
116 return self;
John Beppu019513a1999-12-22 17:57:31 +0000117}
118
John Beppuc0ca4731999-12-21 20:00:35 +0000119
120/* Comparison */
121
John Beppu568cb7b1999-12-22 23:02:12 +0000122/* ascii order */
Erik Andersene49d5ec2000-02-08 19:58:47 +0000123static int compare_ascii(const void *a, const void *b)
John Beppuf3e59041999-12-22 22:24:52 +0000124{
Erik Andersene49d5ec2000-02-08 19:58:47 +0000125 Line **doh;
126 Line *x, *y;
John Beppu568cb7b1999-12-22 23:02:12 +0000127
Erik Andersene49d5ec2000-02-08 19:58:47 +0000128 doh = (Line **) a;
129 x = *doh;
130 doh = (Line **) b;
131 y = *doh;
John Beppu568cb7b1999-12-22 23:02:12 +0000132
Erik Andersene49d5ec2000-02-08 19:58:47 +0000133 // fprintf(stdout, "> %p: %s< %p: %s", x, x->data, y, y->data);
Erik Andersen029011b2000-03-04 21:19:32 +0000134 return APPLY_REVERSE(strcmp(x->data, y->data));
John Beppuf3e59041999-12-22 22:24:52 +0000135}
John Beppuc0ca4731999-12-21 20:00:35 +0000136
John Beppu568cb7b1999-12-22 23:02:12 +0000137/* numeric order */
Erik Andersene49d5ec2000-02-08 19:58:47 +0000138static int compare_numeric(const void *a, const void *b)
John Beppuf3e59041999-12-22 22:24:52 +0000139{
Erik Andersene49d5ec2000-02-08 19:58:47 +0000140 Line **doh;
141 Line *x, *y;
142 int xint, yint;
John Beppuee512a31999-12-23 00:02:49 +0000143
Erik Andersene49d5ec2000-02-08 19:58:47 +0000144 doh = (Line **) a;
145 x = *doh;
146 doh = (Line **) b;
147 y = *doh;
John Beppuee512a31999-12-23 00:02:49 +0000148
Erik Andersene49d5ec2000-02-08 19:58:47 +0000149 xint = strtoul(x->data, NULL, 10);
150 yint = strtoul(y->data, NULL, 10);
John Beppuee512a31999-12-23 00:02:49 +0000151
Erik Andersen029011b2000-03-04 21:19:32 +0000152 return APPLY_REVERSE(xint - yint);
John Beppuf3e59041999-12-22 22:24:52 +0000153}
John Beppuc0ca4731999-12-21 20:00:35 +0000154
155
156/* List */
157
John Beppu38efa791999-12-22 00:30:29 +0000158/* */
Erik Andersene49d5ec2000-02-08 19:58:47 +0000159static List *list_init(List * self)
John Beppu38efa791999-12-22 00:30:29 +0000160{
Erik Andersene49d5ec2000-02-08 19:58:47 +0000161 self->len = 0;
162 self->sorted = NULL;
163 self->head = NULL;
164 self->current = NULL;
165 return self;
John Beppu38efa791999-12-22 00:30:29 +0000166}
John Beppuc0ca4731999-12-21 20:00:35 +0000167
John Beppu38efa791999-12-22 00:30:29 +0000168/* for simplicity, the List gains ownership of the line */
Erik Andersene49d5ec2000-02-08 19:58:47 +0000169static List *list_insert(List * self, Line * line)
John Beppu38efa791999-12-22 00:30:29 +0000170{
Erik Andersene49d5ec2000-02-08 19:58:47 +0000171 if (line == NULL) {
172 return NULL;
173 }
John Beppuc0ca4731999-12-21 20:00:35 +0000174
Erik Andersene49d5ec2000-02-08 19:58:47 +0000175 /* first insertion */
176 if (self->head == NULL) {
177 self->head = line;
178 self->current = line;
John Beppuc0ca4731999-12-21 20:00:35 +0000179
Erik Andersene49d5ec2000-02-08 19:58:47 +0000180 /* all subsequent insertions */
181 } else {
182 self->current->next = line;
183 self->current = line;
184 }
185 self->len++;
186 return self;
John Beppu38efa791999-12-22 00:30:29 +0000187}
188
John Beppuf3e59041999-12-22 22:24:52 +0000189/* order the list according to compare() */
Erik Andersene49d5ec2000-02-08 19:58:47 +0000190static List *list_sort(List * self, Compare * compare)
John Beppuf3e59041999-12-22 22:24:52 +0000191{
Erik Andersene49d5ec2000-02-08 19:58:47 +0000192 int i;
193 Line *line;
John Beppuf3e59041999-12-22 22:24:52 +0000194
Erik Andersene49d5ec2000-02-08 19:58:47 +0000195 /* mallocate array of Line*s */
196 self->sorted = (Line **) malloc(self->len * sizeof(Line *));
197 if (self->sorted == NULL) {
198 return NULL;
199 }
John Beppuf3e59041999-12-22 22:24:52 +0000200
Erik Andersene49d5ec2000-02-08 19:58:47 +0000201 /* fill array w/ List's contents */
202 i = 0;
203 line = self->head;
204 while (line) {
205 self->sorted[i++] = line;
206 line = line->next;
207 }
John Beppuf3e59041999-12-22 22:24:52 +0000208
Erik Andersene49d5ec2000-02-08 19:58:47 +0000209 /* apply qsort */
210 qsort(self->sorted, self->len, sizeof(Line *), compare);
211 return self;
John Beppuf3e59041999-12-22 22:24:52 +0000212}
John Beppu38efa791999-12-22 00:30:29 +0000213
214/* precondition: list must be sorted */
Erik Andersene49d5ec2000-02-08 19:58:47 +0000215static List *list_writeToFile(List * self, FILE * dst)
John Beppu38efa791999-12-22 00:30:29 +0000216{
Erik Andersene49d5ec2000-02-08 19:58:47 +0000217 int i;
218 Line **line = self->sorted;
John Beppuf3e59041999-12-22 22:24:52 +0000219
Erik Andersene49d5ec2000-02-08 19:58:47 +0000220 if (self->sorted == NULL) {
221 return NULL;
222 }
223 for (i = 0; i < self->len; i++) {
224 fprintf(dst, "%s", line[i]->data);
225 }
226 return self;
John Beppu38efa791999-12-22 00:30:29 +0000227}
228
229/* deallocate */
Erik Andersene49d5ec2000-02-08 19:58:47 +0000230static void list_release(List * self)
John Beppu38efa791999-12-22 00:30:29 +0000231{
Erik Andersene49d5ec2000-02-08 19:58:47 +0000232 Line *i;
233 Line *die;
John Beppu019513a1999-12-22 17:57:31 +0000234
Erik Andersene49d5ec2000-02-08 19:58:47 +0000235 i = self->head;
236 while (i) {
237 die = i;
238 i = die->next;
239 line_release(die);
240 }
John Beppu38efa791999-12-22 00:30:29 +0000241}
John Beppuc0ca4731999-12-21 20:00:35 +0000242
243
244/*
245 * I need a list
246 * to insert lines into
247 * then I need to sort this list
248 * and finally print it
249 */
250
Erik Andersene49d5ec2000-02-08 19:58:47 +0000251int sort_main(int argc, char **argv)
John Beppuc0ca4731999-12-21 20:00:35 +0000252{
Erik Andersene49d5ec2000-02-08 19:58:47 +0000253 int i;
254 char opt;
255 List list;
256 Line *l;
257 Compare *compare;
John Beppuc0ca4731999-12-21 20:00:35 +0000258
Erik Andersene49d5ec2000-02-08 19:58:47 +0000259 /* init */
260 compare = compare_ascii;
261 list_init(&list);
John Beppuc0ca4731999-12-21 20:00:35 +0000262
Erik Andersene49d5ec2000-02-08 19:58:47 +0000263 /* parse argv[] */
264 for (i = 1; i < argc; i++) {
265 if (argv[i][0] == '-') {
266 opt = argv[i][1];
267 switch (opt) {
Erik Andersene49d5ec2000-02-08 19:58:47 +0000268 case 'h':
269 usage(sort_usage);
270 break;
271 case 'n':
Erik Andersen029011b2000-03-04 21:19:32 +0000272 /* numeric comparison */
Erik Andersene49d5ec2000-02-08 19:58:47 +0000273 compare = compare_numeric;
274 break;
Erik Andersen029011b2000-03-04 21:19:32 +0000275#ifdef BB_FEATURE_SORT_REVERSE
Erik Andersene49d5ec2000-02-08 19:58:47 +0000276 case 'r':
277 /* reverse */
Erik Andersen029011b2000-03-04 21:19:32 +0000278 reverse = 1;
Erik Andersene49d5ec2000-02-08 19:58:47 +0000279 break;
Erik Andersen029011b2000-03-04 21:19:32 +0000280#endif
Erik Andersene49d5ec2000-02-08 19:58:47 +0000281 default:
282 fprintf(stderr, "sort: invalid option -- %c\n", opt);
283 usage(sort_usage);
284 }
285 } else {
286 break;
287 }
288 }
289
290 /* this could be factored better */
291
292 /* work w/ stdin */
293 if (i >= argc) {
294 while ((l = line_newFromFile(stdin))) {
295 list_insert(&list, l);
296 }
297 list_sort(&list, compare);
298 list_writeToFile(&list, stdout);
299 list_release(&list);
300
301 /* work w/ what's left in argv[] */
John Beppuc0ca4731999-12-21 20:00:35 +0000302 } else {
Erik Andersene49d5ec2000-02-08 19:58:47 +0000303 FILE *src;
304
305 for (; i < argc; i++) {
306 src = fopen(argv[i], "r");
307 if (src == NULL) {
308 break;
309 }
310 while ((l = line_newFromFile(src))) {
311 list_insert(&list, l);
312 }
313 fclose(src);
314 }
315 list_sort(&list, compare);
316 list_writeToFile(&list, stdout);
317 list_release(&list);
John Beppuc0ca4731999-12-21 20:00:35 +0000318 }
John Beppuc0ca4731999-12-21 20:00:35 +0000319
Erik Andersene49d5ec2000-02-08 19:58:47 +0000320 exit(0);
John Beppuc0ca4731999-12-21 20:00:35 +0000321}
322
Erik Andersen5e1189e2000-04-15 16:34:54 +0000323/* $Id: sort.c,v 1.14 2000/04/15 16:34:54 erik Exp $ */