blob: 609c5e08cf4eff25b43c5c4f2fcc05b50451437e [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 *
6 * Copyright (C) 1999 by Lineo, inc.
7 * 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 Andersene49d5ec2000-02-08 19:58:47 +000032static const char sort_usage[] = "sort [OPTION]... [FILE]...\n\n";
John Beppuc0ca4731999-12-21 20:00:35 +000033
John Beppuf3e59041999-12-22 22:24:52 +000034/* typedefs _______________________________________________________________ */
John Beppuc0ca4731999-12-21 20:00:35 +000035
36/* line node */
John Beppuf3e59041999-12-22 22:24:52 +000037typedef struct Line {
Erik Andersene49d5ec2000-02-08 19:58:47 +000038 char *data; /* line data */
39 struct Line *next; /* pointer to next line node */
John Beppuc0ca4731999-12-21 20:00:35 +000040} Line;
41
42/* singly-linked list of lines */
43typedef struct {
Erik Andersene49d5ec2000-02-08 19:58:47 +000044 int len; /* number of Lines */
45 Line **sorted; /* array fed to qsort */
John Beppu38efa791999-12-22 00:30:29 +000046
Erik Andersene49d5ec2000-02-08 19:58:47 +000047 Line *head; /* head of List */
48 Line *current; /* current Line */
John Beppuc0ca4731999-12-21 20:00:35 +000049} List;
50
John Beppuf3e59041999-12-22 22:24:52 +000051/* comparison function */
Erik Andersene49d5ec2000-02-08 19:58:47 +000052typedef int (Compare) (const void *, const void *);
John Beppuf3e59041999-12-22 22:24:52 +000053
John Beppuc0ca4731999-12-21 20:00:35 +000054
John Beppu38efa791999-12-22 00:30:29 +000055/* methods ________________________________________________________________ */
John Beppuc0ca4731999-12-21 20:00:35 +000056
57static const int max = 1024;
58
John Beppu38efa791999-12-22 00:30:29 +000059/* mallocate Line */
Erik Andersene49d5ec2000-02-08 19:58:47 +000060static Line *line_alloc()
John Beppuc0ca4731999-12-21 20:00:35 +000061{
Erik Andersene49d5ec2000-02-08 19:58:47 +000062 Line *self;
63
64 self = malloc(1 * sizeof(Line));
65 return self;
John Beppu38efa791999-12-22 00:30:29 +000066}
67
68/* Initialize Line with string */
Erik Andersene49d5ec2000-02-08 19:58:47 +000069static Line *line_init(Line * self, const char *string)
John Beppu38efa791999-12-22 00:30:29 +000070{
Erik Andersene49d5ec2000-02-08 19:58:47 +000071 self->data = malloc((strlen(string) + 1) * sizeof(char));
72
73 if (self->data == NULL) {
74 return NULL;
75 }
76 strcpy(self->data, string);
77 self->next = NULL;
78 return self;
John Beppu38efa791999-12-22 00:30:29 +000079}
80
81/* 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 char buffer[max];
85 Line *self;
John Beppu38efa791999-12-22 00:30:29 +000086
Erik Andersene49d5ec2000-02-08 19:58:47 +000087 if (fgets(buffer, max, src)) {
88 self = line_alloc();
89 if (self == NULL) {
90 return NULL;
91 }
92 line_init(self, buffer);
93 return self;
94 }
95 return NULL;
John Beppuc0ca4731999-12-21 20:00:35 +000096}
97
John Beppu019513a1999-12-22 17:57:31 +000098/* Line destructor */
Erik Andersene49d5ec2000-02-08 19:58:47 +000099static Line *line_release(Line * self)
John Beppu019513a1999-12-22 17:57:31 +0000100{
Erik Andersene49d5ec2000-02-08 19:58:47 +0000101 if (self->data) {
102 free(self->data);
103 free(self);
104 }
105 return self;
John Beppu019513a1999-12-22 17:57:31 +0000106}
107
John Beppuc0ca4731999-12-21 20:00:35 +0000108
109/* Comparison */
110
John Beppu568cb7b1999-12-22 23:02:12 +0000111/* ascii order */
Erik Andersene49d5ec2000-02-08 19:58:47 +0000112static int compare_ascii(const void *a, const void *b)
John Beppuf3e59041999-12-22 22:24:52 +0000113{
Erik Andersene49d5ec2000-02-08 19:58:47 +0000114 Line **doh;
115 Line *x, *y;
John Beppu568cb7b1999-12-22 23:02:12 +0000116
Erik Andersene49d5ec2000-02-08 19:58:47 +0000117 doh = (Line **) a;
118 x = *doh;
119 doh = (Line **) b;
120 y = *doh;
John Beppu568cb7b1999-12-22 23:02:12 +0000121
Erik Andersene49d5ec2000-02-08 19:58:47 +0000122 // fprintf(stdout, "> %p: %s< %p: %s", x, x->data, y, y->data);
123 return strcmp(x->data, y->data);
John Beppuf3e59041999-12-22 22:24:52 +0000124}
John Beppuc0ca4731999-12-21 20:00:35 +0000125
John Beppu568cb7b1999-12-22 23:02:12 +0000126/* numeric order */
Erik Andersene49d5ec2000-02-08 19:58:47 +0000127static int compare_numeric(const void *a, const void *b)
John Beppuf3e59041999-12-22 22:24:52 +0000128{
Erik Andersene49d5ec2000-02-08 19:58:47 +0000129 Line **doh;
130 Line *x, *y;
131 int xint, yint;
John Beppuee512a31999-12-23 00:02:49 +0000132
Erik Andersene49d5ec2000-02-08 19:58:47 +0000133 doh = (Line **) a;
134 x = *doh;
135 doh = (Line **) b;
136 y = *doh;
John Beppuee512a31999-12-23 00:02:49 +0000137
Erik Andersene49d5ec2000-02-08 19:58:47 +0000138 xint = strtoul(x->data, NULL, 10);
139 yint = strtoul(y->data, NULL, 10);
John Beppuee512a31999-12-23 00:02:49 +0000140
Erik Andersene49d5ec2000-02-08 19:58:47 +0000141 return (xint - yint);
John Beppuf3e59041999-12-22 22:24:52 +0000142}
John Beppuc0ca4731999-12-21 20:00:35 +0000143
144
145/* List */
146
John Beppu38efa791999-12-22 00:30:29 +0000147/* */
Erik Andersene49d5ec2000-02-08 19:58:47 +0000148static List *list_init(List * self)
John Beppu38efa791999-12-22 00:30:29 +0000149{
Erik Andersene49d5ec2000-02-08 19:58:47 +0000150 self->len = 0;
151 self->sorted = NULL;
152 self->head = NULL;
153 self->current = NULL;
154 return self;
John Beppu38efa791999-12-22 00:30:29 +0000155}
John Beppuc0ca4731999-12-21 20:00:35 +0000156
John Beppu38efa791999-12-22 00:30:29 +0000157/* for simplicity, the List gains ownership of the line */
Erik Andersene49d5ec2000-02-08 19:58:47 +0000158static List *list_insert(List * self, Line * line)
John Beppu38efa791999-12-22 00:30:29 +0000159{
Erik Andersene49d5ec2000-02-08 19:58:47 +0000160 if (line == NULL) {
161 return NULL;
162 }
John Beppuc0ca4731999-12-21 20:00:35 +0000163
Erik Andersene49d5ec2000-02-08 19:58:47 +0000164 /* first insertion */
165 if (self->head == NULL) {
166 self->head = line;
167 self->current = line;
John Beppuc0ca4731999-12-21 20:00:35 +0000168
Erik Andersene49d5ec2000-02-08 19:58:47 +0000169 /* all subsequent insertions */
170 } else {
171 self->current->next = line;
172 self->current = line;
173 }
174 self->len++;
175 return self;
John Beppu38efa791999-12-22 00:30:29 +0000176}
177
John Beppuf3e59041999-12-22 22:24:52 +0000178/* order the list according to compare() */
Erik Andersene49d5ec2000-02-08 19:58:47 +0000179static List *list_sort(List * self, Compare * compare)
John Beppuf3e59041999-12-22 22:24:52 +0000180{
Erik Andersene49d5ec2000-02-08 19:58:47 +0000181 int i;
182 Line *line;
John Beppuf3e59041999-12-22 22:24:52 +0000183
Erik Andersene49d5ec2000-02-08 19:58:47 +0000184 /* mallocate array of Line*s */
185 self->sorted = (Line **) malloc(self->len * sizeof(Line *));
186 if (self->sorted == NULL) {
187 return NULL;
188 }
John Beppuf3e59041999-12-22 22:24:52 +0000189
Erik Andersene49d5ec2000-02-08 19:58:47 +0000190 /* fill array w/ List's contents */
191 i = 0;
192 line = self->head;
193 while (line) {
194 self->sorted[i++] = line;
195 line = line->next;
196 }
John Beppuf3e59041999-12-22 22:24:52 +0000197
Erik Andersene49d5ec2000-02-08 19:58:47 +0000198 /* apply qsort */
199 qsort(self->sorted, self->len, sizeof(Line *), compare);
200 return self;
John Beppuf3e59041999-12-22 22:24:52 +0000201}
John Beppu38efa791999-12-22 00:30:29 +0000202
203/* precondition: list must be sorted */
Erik Andersene49d5ec2000-02-08 19:58:47 +0000204static List *list_writeToFile(List * self, FILE * dst)
John Beppu38efa791999-12-22 00:30:29 +0000205{
Erik Andersene49d5ec2000-02-08 19:58:47 +0000206 int i;
207 Line **line = self->sorted;
John Beppuf3e59041999-12-22 22:24:52 +0000208
Erik Andersene49d5ec2000-02-08 19:58:47 +0000209 if (self->sorted == NULL) {
210 return NULL;
211 }
212 for (i = 0; i < self->len; i++) {
213 fprintf(dst, "%s", line[i]->data);
214 }
215 return self;
John Beppu38efa791999-12-22 00:30:29 +0000216}
217
218/* deallocate */
Erik Andersene49d5ec2000-02-08 19:58:47 +0000219static void list_release(List * self)
John Beppu38efa791999-12-22 00:30:29 +0000220{
Erik Andersene49d5ec2000-02-08 19:58:47 +0000221 Line *i;
222 Line *die;
John Beppu019513a1999-12-22 17:57:31 +0000223
Erik Andersene49d5ec2000-02-08 19:58:47 +0000224 i = self->head;
225 while (i) {
226 die = i;
227 i = die->next;
228 line_release(die);
229 }
John Beppu38efa791999-12-22 00:30:29 +0000230}
John Beppuc0ca4731999-12-21 20:00:35 +0000231
232
233/*
234 * I need a list
235 * to insert lines into
236 * then I need to sort this list
237 * and finally print it
238 */
239
Erik Andersene49d5ec2000-02-08 19:58:47 +0000240int sort_main(int argc, char **argv)
John Beppuc0ca4731999-12-21 20:00:35 +0000241{
Erik Andersene49d5ec2000-02-08 19:58:47 +0000242 int i;
243 char opt;
244 List list;
245 Line *l;
246 Compare *compare;
John Beppuc0ca4731999-12-21 20:00:35 +0000247
Erik Andersene49d5ec2000-02-08 19:58:47 +0000248 /* init */
249 compare = compare_ascii;
250 list_init(&list);
John Beppuc0ca4731999-12-21 20:00:35 +0000251
Erik Andersene49d5ec2000-02-08 19:58:47 +0000252 /* parse argv[] */
253 for (i = 1; i < argc; i++) {
254 if (argv[i][0] == '-') {
255 opt = argv[i][1];
256 switch (opt) {
257 case 'g':
258 /* what's the diff between -g && -n? */
259 compare = compare_numeric;
260 break;
261 case 'h':
262 usage(sort_usage);
263 break;
264 case 'n':
265 /* what's the diff between -g && -n? */
266 compare = compare_numeric;
267 break;
268 case 'r':
269 /* reverse */
270 break;
271 default:
272 fprintf(stderr, "sort: invalid option -- %c\n", opt);
273 usage(sort_usage);
274 }
275 } else {
276 break;
277 }
278 }
279
280 /* this could be factored better */
281
282 /* work w/ stdin */
283 if (i >= argc) {
284 while ((l = line_newFromFile(stdin))) {
285 list_insert(&list, l);
286 }
287 list_sort(&list, compare);
288 list_writeToFile(&list, stdout);
289 list_release(&list);
290
291 /* work w/ what's left in argv[] */
John Beppuc0ca4731999-12-21 20:00:35 +0000292 } else {
Erik Andersene49d5ec2000-02-08 19:58:47 +0000293 FILE *src;
294
295 for (; i < argc; i++) {
296 src = fopen(argv[i], "r");
297 if (src == NULL) {
298 break;
299 }
300 while ((l = line_newFromFile(src))) {
301 list_insert(&list, l);
302 }
303 fclose(src);
304 }
305 list_sort(&list, compare);
306 list_writeToFile(&list, stdout);
307 list_release(&list);
John Beppuc0ca4731999-12-21 20:00:35 +0000308 }
John Beppuc0ca4731999-12-21 20:00:35 +0000309
Erik Andersene49d5ec2000-02-08 19:58:47 +0000310 exit(0);
John Beppuc0ca4731999-12-21 20:00:35 +0000311}
312
Erik Andersene49d5ec2000-02-08 19:58:47 +0000313/* $Id: sort.c,v 1.11 2000/02/08 19:58:47 erik Exp $ */