blob: 6af5c4df302af127b07c402c494fdd0d1e4134e0 [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 +000032#ifdef BB_FEATURE_SORT_REVERSE
33#define APPLY_REVERSE(x) (reverse ? -(x) : (x))
34static int reverse = 0;
35#else
36#define APPLY_REVERSE(x) (x)
37#endif
John Beppuc0ca4731999-12-21 20:00:35 +000038
John Beppuf3e59041999-12-22 22:24:52 +000039/* typedefs _______________________________________________________________ */
John Beppuc0ca4731999-12-21 20:00:35 +000040
41/* line node */
John Beppuf3e59041999-12-22 22:24:52 +000042typedef struct Line {
Erik Andersene49d5ec2000-02-08 19:58:47 +000043 char *data; /* line data */
44 struct Line *next; /* pointer to next line node */
John Beppuc0ca4731999-12-21 20:00:35 +000045} Line;
46
47/* singly-linked list of lines */
48typedef struct {
Erik Andersene49d5ec2000-02-08 19:58:47 +000049 int len; /* number of Lines */
50 Line **sorted; /* array fed to qsort */
Erik Andersene49d5ec2000-02-08 19:58:47 +000051 Line *head; /* head of List */
52 Line *current; /* current Line */
John Beppuc0ca4731999-12-21 20:00:35 +000053} List;
54
John Beppuf3e59041999-12-22 22:24:52 +000055/* comparison function */
Erik Andersene49d5ec2000-02-08 19:58:47 +000056typedef int (Compare) (const void *, const void *);
John Beppuf3e59041999-12-22 22:24:52 +000057
John Beppuc0ca4731999-12-21 20:00:35 +000058
John Beppu38efa791999-12-22 00:30:29 +000059/* methods ________________________________________________________________ */
John Beppuc0ca4731999-12-21 20:00:35 +000060
61static const int max = 1024;
62
John Beppu38efa791999-12-22 00:30:29 +000063/* mallocate Line */
Erik Andersene49d5ec2000-02-08 19:58:47 +000064static Line *line_alloc()
John Beppuc0ca4731999-12-21 20:00:35 +000065{
Erik Andersene49d5ec2000-02-08 19:58:47 +000066 Line *self;
Erik Andersene49d5ec2000-02-08 19:58:47 +000067 self = malloc(1 * sizeof(Line));
68 return self;
John Beppu38efa791999-12-22 00:30:29 +000069}
70
John Beppu38efa791999-12-22 00:30:29 +000071/* Construct Line from FILE* */
Erik Andersene49d5ec2000-02-08 19:58:47 +000072static Line *line_newFromFile(FILE * src)
John Beppu38efa791999-12-22 00:30:29 +000073{
Erik Andersene49d5ec2000-02-08 19:58:47 +000074 Line *self;
John Beppu5a728cf2000-04-17 04:22:09 +000075 char *cstring = NULL;
John Beppu38efa791999-12-22 00:30:29 +000076
Mark Whitley1ca41772000-06-28 22:15:26 +000077 if ((cstring = get_line_from_file(src))) {
Erik Andersene49d5ec2000-02-08 19:58:47 +000078 self = line_alloc();
79 if (self == NULL) {
80 return NULL;
81 }
John Beppu5a728cf2000-04-17 04:22:09 +000082 self->data = cstring;
83 self->next = NULL;
Erik Andersene49d5ec2000-02-08 19:58:47 +000084 return self;
85 }
86 return NULL;
John Beppuc0ca4731999-12-21 20:00:35 +000087}
88
John Beppu019513a1999-12-22 17:57:31 +000089/* Line destructor */
Erik Andersene49d5ec2000-02-08 19:58:47 +000090static Line *line_release(Line * self)
John Beppu019513a1999-12-22 17:57:31 +000091{
Erik Andersene49d5ec2000-02-08 19:58:47 +000092 if (self->data) {
93 free(self->data);
94 free(self);
95 }
96 return self;
John Beppu019513a1999-12-22 17:57:31 +000097}
98
John Beppuc0ca4731999-12-21 20:00:35 +000099
100/* Comparison */
101
John Beppu568cb7b1999-12-22 23:02:12 +0000102/* ascii order */
Erik Andersene49d5ec2000-02-08 19:58:47 +0000103static int compare_ascii(const void *a, const void *b)
John Beppuf3e59041999-12-22 22:24:52 +0000104{
Erik Andersene49d5ec2000-02-08 19:58:47 +0000105 Line **doh;
106 Line *x, *y;
John Beppu568cb7b1999-12-22 23:02:12 +0000107
Erik Andersene49d5ec2000-02-08 19:58:47 +0000108 doh = (Line **) a;
109 x = *doh;
110 doh = (Line **) b;
111 y = *doh;
John Beppu568cb7b1999-12-22 23:02:12 +0000112
Erik Andersene49d5ec2000-02-08 19:58:47 +0000113 // fprintf(stdout, "> %p: %s< %p: %s", x, x->data, y, y->data);
Erik Andersen029011b2000-03-04 21:19:32 +0000114 return APPLY_REVERSE(strcmp(x->data, y->data));
John Beppuf3e59041999-12-22 22:24:52 +0000115}
John Beppuc0ca4731999-12-21 20:00:35 +0000116
John Beppu568cb7b1999-12-22 23:02:12 +0000117/* numeric order */
Erik Andersene49d5ec2000-02-08 19:58:47 +0000118static int compare_numeric(const void *a, const void *b)
John Beppuf3e59041999-12-22 22:24:52 +0000119{
Erik Andersene49d5ec2000-02-08 19:58:47 +0000120 Line **doh;
121 Line *x, *y;
122 int xint, yint;
John Beppuee512a31999-12-23 00:02:49 +0000123
Erik Andersene49d5ec2000-02-08 19:58:47 +0000124 doh = (Line **) a;
125 x = *doh;
126 doh = (Line **) b;
127 y = *doh;
John Beppuee512a31999-12-23 00:02:49 +0000128
Erik Andersene49d5ec2000-02-08 19:58:47 +0000129 xint = strtoul(x->data, NULL, 10);
130 yint = strtoul(y->data, NULL, 10);
John Beppuee512a31999-12-23 00:02:49 +0000131
Erik Andersen029011b2000-03-04 21:19:32 +0000132 return APPLY_REVERSE(xint - yint);
John Beppuf3e59041999-12-22 22:24:52 +0000133}
John Beppuc0ca4731999-12-21 20:00:35 +0000134
135
136/* List */
137
John Beppu38efa791999-12-22 00:30:29 +0000138/* */
Erik Andersene49d5ec2000-02-08 19:58:47 +0000139static List *list_init(List * self)
John Beppu38efa791999-12-22 00:30:29 +0000140{
Erik Andersene49d5ec2000-02-08 19:58:47 +0000141 self->len = 0;
142 self->sorted = NULL;
143 self->head = NULL;
144 self->current = NULL;
145 return self;
John Beppu38efa791999-12-22 00:30:29 +0000146}
John Beppuc0ca4731999-12-21 20:00:35 +0000147
John Beppu38efa791999-12-22 00:30:29 +0000148/* for simplicity, the List gains ownership of the line */
Erik Andersene49d5ec2000-02-08 19:58:47 +0000149static List *list_insert(List * self, Line * line)
John Beppu38efa791999-12-22 00:30:29 +0000150{
Erik Andersene49d5ec2000-02-08 19:58:47 +0000151 if (line == NULL) {
152 return NULL;
153 }
John Beppuc0ca4731999-12-21 20:00:35 +0000154
Erik Andersene49d5ec2000-02-08 19:58:47 +0000155 /* first insertion */
156 if (self->head == NULL) {
157 self->head = line;
158 self->current = line;
John Beppuc0ca4731999-12-21 20:00:35 +0000159
John Beppu5a728cf2000-04-17 04:22:09 +0000160 /* all subsequent insertions */
Erik Andersene49d5ec2000-02-08 19:58:47 +0000161 } else {
162 self->current->next = line;
163 self->current = line;
164 }
165 self->len++;
166 return self;
John Beppu38efa791999-12-22 00:30:29 +0000167}
168
John Beppuf3e59041999-12-22 22:24:52 +0000169/* order the list according to compare() */
Erik Andersene49d5ec2000-02-08 19:58:47 +0000170static List *list_sort(List * self, Compare * compare)
John Beppuf3e59041999-12-22 22:24:52 +0000171{
Erik Andersene49d5ec2000-02-08 19:58:47 +0000172 int i;
173 Line *line;
John Beppuf3e59041999-12-22 22:24:52 +0000174
Erik Andersene49d5ec2000-02-08 19:58:47 +0000175 /* mallocate array of Line*s */
176 self->sorted = (Line **) malloc(self->len * sizeof(Line *));
177 if (self->sorted == NULL) {
178 return NULL;
179 }
John Beppuf3e59041999-12-22 22:24:52 +0000180
Erik Andersene49d5ec2000-02-08 19:58:47 +0000181 /* fill array w/ List's contents */
182 i = 0;
183 line = self->head;
184 while (line) {
185 self->sorted[i++] = line;
186 line = line->next;
187 }
John Beppuf3e59041999-12-22 22:24:52 +0000188
Erik Andersene49d5ec2000-02-08 19:58:47 +0000189 /* apply qsort */
190 qsort(self->sorted, self->len, sizeof(Line *), compare);
191 return self;
John Beppuf3e59041999-12-22 22:24:52 +0000192}
John Beppu38efa791999-12-22 00:30:29 +0000193
194/* precondition: list must be sorted */
Erik Andersene49d5ec2000-02-08 19:58:47 +0000195static List *list_writeToFile(List * self, FILE * dst)
John Beppu38efa791999-12-22 00:30:29 +0000196{
Erik Andersene49d5ec2000-02-08 19:58:47 +0000197 int i;
198 Line **line = self->sorted;
John Beppuf3e59041999-12-22 22:24:52 +0000199
Erik Andersene49d5ec2000-02-08 19:58:47 +0000200 if (self->sorted == NULL) {
201 return NULL;
202 }
203 for (i = 0; i < self->len; i++) {
204 fprintf(dst, "%s", line[i]->data);
205 }
206 return self;
John Beppu38efa791999-12-22 00:30:29 +0000207}
208
209/* deallocate */
Erik Andersene49d5ec2000-02-08 19:58:47 +0000210static void list_release(List * self)
John Beppu38efa791999-12-22 00:30:29 +0000211{
Erik Andersene49d5ec2000-02-08 19:58:47 +0000212 Line *i;
213 Line *die;
John Beppu019513a1999-12-22 17:57:31 +0000214
Erik Andersene49d5ec2000-02-08 19:58:47 +0000215 i = self->head;
216 while (i) {
217 die = i;
218 i = die->next;
219 line_release(die);
220 }
John Beppu38efa791999-12-22 00:30:29 +0000221}
John Beppuc0ca4731999-12-21 20:00:35 +0000222
223
John Beppuc0ca4731999-12-21 20:00:35 +0000224
Erik Andersene49d5ec2000-02-08 19:58:47 +0000225int sort_main(int argc, char **argv)
John Beppuc0ca4731999-12-21 20:00:35 +0000226{
Erik Andersene49d5ec2000-02-08 19:58:47 +0000227 int i;
228 char opt;
229 List list;
230 Line *l;
231 Compare *compare;
John Beppuc0ca4731999-12-21 20:00:35 +0000232
Erik Andersene49d5ec2000-02-08 19:58:47 +0000233 /* init */
234 compare = compare_ascii;
235 list_init(&list);
John Beppuc0ca4731999-12-21 20:00:35 +0000236
Erik Andersene49d5ec2000-02-08 19:58:47 +0000237 /* parse argv[] */
238 for (i = 1; i < argc; i++) {
239 if (argv[i][0] == '-') {
240 opt = argv[i][1];
241 switch (opt) {
Erik Andersene49d5ec2000-02-08 19:58:47 +0000242 case 'h':
243 usage(sort_usage);
244 break;
245 case 'n':
Erik Andersen029011b2000-03-04 21:19:32 +0000246 /* numeric comparison */
Erik Andersene49d5ec2000-02-08 19:58:47 +0000247 compare = compare_numeric;
248 break;
Erik Andersen029011b2000-03-04 21:19:32 +0000249#ifdef BB_FEATURE_SORT_REVERSE
Erik Andersene49d5ec2000-02-08 19:58:47 +0000250 case 'r':
251 /* reverse */
Erik Andersen029011b2000-03-04 21:19:32 +0000252 reverse = 1;
Erik Andersene49d5ec2000-02-08 19:58:47 +0000253 break;
Erik Andersen029011b2000-03-04 21:19:32 +0000254#endif
Erik Andersene49d5ec2000-02-08 19:58:47 +0000255 default:
Matt Kraaid537a952000-07-14 01:51:25 +0000256 errorMsg("invalid option -- %c\n", opt);
Erik Andersene49d5ec2000-02-08 19:58:47 +0000257 usage(sort_usage);
258 }
259 } else {
260 break;
261 }
262 }
263
264 /* this could be factored better */
265
266 /* work w/ stdin */
267 if (i >= argc) {
268 while ((l = line_newFromFile(stdin))) {
269 list_insert(&list, l);
270 }
271 list_sort(&list, compare);
272 list_writeToFile(&list, stdout);
273 list_release(&list);
274
275 /* work w/ what's left in argv[] */
John Beppuc0ca4731999-12-21 20:00:35 +0000276 } else {
Erik Andersene49d5ec2000-02-08 19:58:47 +0000277 FILE *src;
278
279 for (; i < argc; i++) {
280 src = fopen(argv[i], "r");
281 if (src == NULL) {
282 break;
283 }
284 while ((l = line_newFromFile(src))) {
285 list_insert(&list, l);
286 }
287 fclose(src);
288 }
289 list_sort(&list, compare);
290 list_writeToFile(&list, stdout);
291 list_release(&list);
John Beppuc0ca4731999-12-21 20:00:35 +0000292 }
John Beppuc0ca4731999-12-21 20:00:35 +0000293
Eric Andersenb6106152000-06-19 17:25:40 +0000294 return(0);
John Beppuc0ca4731999-12-21 20:00:35 +0000295}
296
Matt Kraaibf181b92000-07-16 20:57:15 +0000297/* $Id: sort.c,v 1.20 2000/07/16 20:57:15 kraai Exp $ */