blob: 0fe7bf99bb0ce7532ddc55669aa5e08706cbc35b [file] [log] [blame]
John Beppuc0ca4731999-12-21 20:00:35 +00001/*
John Beppu568cb7b1999-12-22 23:02:12 +00002 * Mini sort implementation for busybox
John Beppuc0ca4731999-12-21 20:00:35 +00003 *
4 *
5 * Copyright (C) 1999 by Lineo, inc.
6 * Written by John Beppu <beppu@lineo.com>
7 *
8 * This program is free software; you can redistribute it and/or modify
9 * it under the terms of the GNU General Public License as published by
10 * the Free Software Foundation; either version 2 of the License, or
11 * (at your option) any later version.
12 *
13 * This program is distributed in the hope that it will be useful,
14 * but WITHOUT ANY WARRANTY; without even the implied warranty of
15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
16 * General Public License for more details.
17 *
18 * You should have received a copy of the GNU General Public License
19 * along with this program; if not, write to the Free Software
20 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
21 *
22 */
23
24#include "internal.h"
25#include <sys/types.h>
26#include <fcntl.h>
27#include <dirent.h>
28#include <stdio.h>
29#include <errno.h>
30
31static const char sort_usage[] =
32"Usage: sort [OPTION]... [FILE]...\n\n"
33;
34
John Beppuf3e59041999-12-22 22:24:52 +000035/* typedefs _______________________________________________________________ */
John Beppuc0ca4731999-12-21 20:00:35 +000036
37/* line node */
John Beppuf3e59041999-12-22 22:24:52 +000038typedef struct Line {
39 char *data; /* line data */
40 struct Line *next; /* pointer to next line node */
John Beppuc0ca4731999-12-21 20:00:35 +000041} Line;
42
43/* singly-linked list of lines */
44typedef struct {
John Beppuf3e59041999-12-22 22:24:52 +000045 int len; /* number of Lines */
46 Line **sorted; /* array fed to qsort */
John Beppu38efa791999-12-22 00:30:29 +000047
John Beppuf3e59041999-12-22 22:24:52 +000048 Line *head; /* head of List */
49 Line *current; /* current Line */
John Beppuc0ca4731999-12-21 20:00:35 +000050} List;
51
John Beppuf3e59041999-12-22 22:24:52 +000052/* comparison function */
53typedef int (Compare)(const void *, const void *);
54
John Beppuc0ca4731999-12-21 20:00:35 +000055
John Beppu38efa791999-12-22 00:30:29 +000056/* methods ________________________________________________________________ */
John Beppuc0ca4731999-12-21 20:00:35 +000057
58static const int max = 1024;
59
John Beppu38efa791999-12-22 00:30:29 +000060/* mallocate Line */
John Beppuc0ca4731999-12-21 20:00:35 +000061static Line *
John Beppu38efa791999-12-22 00:30:29 +000062line_alloc()
John Beppuc0ca4731999-12-21 20:00:35 +000063{
John Beppu38efa791999-12-22 00:30:29 +000064 Line *self;
65 self = malloc(1 * sizeof(Line));
66 return self;
67}
68
69/* Initialize Line with string */
70static Line *
71line_init(Line *self, const char *string)
72{
73 self->data = malloc((strlen(string) + 1) * sizeof(char));
74 if (self->data == NULL) { return NULL; }
75 strcpy(self->data, string);
76 self->next = NULL;
77 return self;
78}
79
80/* Construct Line from FILE* */
81static Line *
82line_newFromFile(FILE *src)
83{
84 char buffer[max];
85 Line *self;
86
87 if (fgets(buffer, max, src)) {
88 self = line_alloc();
89 if (self == NULL) { return NULL; }
90 line_init(self, buffer);
91 return self;
92 }
93 return NULL;
John Beppuc0ca4731999-12-21 20:00:35 +000094}
95
John Beppu019513a1999-12-22 17:57:31 +000096/* Line destructor */
97static Line *
98line_release(Line *self)
99{
100 if (self->data) {
101 free(self->data);
102 free(self);
103 }
104 return self;
105}
106
John Beppuc0ca4731999-12-21 20:00:35 +0000107
108/* Comparison */
109
John Beppu568cb7b1999-12-22 23:02:12 +0000110/* ascii order */
John Beppuc0ca4731999-12-21 20:00:35 +0000111static int
John Beppuf3e59041999-12-22 22:24:52 +0000112compare_ascii(const void *a, const void *b)
113{
John Beppu568cb7b1999-12-22 23:02:12 +0000114 Line **doh;
115 Line *x, *y;
116
117 doh = (Line **) a;
John Beppuee512a31999-12-23 00:02:49 +0000118 x = *doh;
John Beppu568cb7b1999-12-22 23:02:12 +0000119 doh = (Line **) b;
John Beppuee512a31999-12-23 00:02:49 +0000120 y = *doh;
John Beppu568cb7b1999-12-22 23:02:12 +0000121
122 // 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 */
John Beppuc0ca4731999-12-21 20:00:35 +0000127static int
John Beppuf3e59041999-12-22 22:24:52 +0000128compare_numeric(const void *a, const void *b)
129{
John Beppuee512a31999-12-23 00:02:49 +0000130 Line **doh;
131 Line *x, *y;
132 int xint, yint;
133
134 doh = (Line **) a;
135 x = *doh;
136 doh = (Line **) b;
137 y = *doh;
138
139 xint = strtoul(x->data, NULL, 10);
140 yint = strtoul(y->data, NULL, 10);
141
142 return (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/* */
149static List *
150list_init(List *self)
151{
152 self->len = 0;
153 self->sorted = NULL;
154 self->head = NULL;
155 self->current = NULL;
156 return self;
157}
John Beppuc0ca4731999-12-21 20:00:35 +0000158
John Beppu38efa791999-12-22 00:30:29 +0000159/* for simplicity, the List gains ownership of the line */
John Beppuf3e59041999-12-22 22:24:52 +0000160static List *
John Beppu38efa791999-12-22 00:30:29 +0000161list_insert(List *self, Line *line)
162{
163 if (line == NULL) { return NULL; }
John Beppuc0ca4731999-12-21 20:00:35 +0000164
John Beppu38efa791999-12-22 00:30:29 +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 Beppu38efa791999-12-22 00:30:29 +0000170 /* all subsequent insertions */
171 } else {
John Beppuf3e59041999-12-22 22:24:52 +0000172 self->current->next = line;
John Beppu38efa791999-12-22 00:30:29 +0000173 self->current = line;
174 }
175 self->len++;
176 return self;
177}
178
John Beppuf3e59041999-12-22 22:24:52 +0000179/* order the list according to compare() */
John Beppu38efa791999-12-22 00:30:29 +0000180static List *
John Beppuf3e59041999-12-22 22:24:52 +0000181list_sort(List *self, Compare *compare)
182{
183 int i;
184 Line *line;
185
186 /* mallocate array of Line*s */
187 self->sorted = (Line **) malloc(self->len * sizeof(Line*));
188 if (self->sorted == NULL) { return NULL; }
189
190 /* 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 }
197
198 /* apply qsort */
John Beppu568cb7b1999-12-22 23:02:12 +0000199 qsort(self->sorted, self->len, sizeof(Line*), compare);
John Beppuf3e59041999-12-22 22:24:52 +0000200 return self;
201}
John Beppu38efa791999-12-22 00:30:29 +0000202
203/* precondition: list must be sorted */
204static List *
205list_writeToFile(List *self, FILE* dst)
206{
John Beppuf3e59041999-12-22 22:24:52 +0000207 int i;
208 Line **line = self->sorted;
209
John Beppu38efa791999-12-22 00:30:29 +0000210 if (self->sorted == NULL) { return NULL; }
John Beppuf3e59041999-12-22 22:24:52 +0000211 for (i = 0; i < self->len; i++) {
212 fprintf(dst, "%s", line[i]->data);
213 }
214 return self;
John Beppu38efa791999-12-22 00:30:29 +0000215}
216
217/* deallocate */
John Beppuf3e59041999-12-22 22:24:52 +0000218static void
John Beppu38efa791999-12-22 00:30:29 +0000219list_release(List *self)
220{
John Beppu019513a1999-12-22 17:57:31 +0000221 Line *i;
222 Line *die;
223
224 i = self->head;
225 while (i) {
226 die = i;
227 i = die->next;
John Beppuf3e59041999-12-22 22:24:52 +0000228 line_release(die);
John Beppu019513a1999-12-22 17:57:31 +0000229 }
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
240int
241sort_main(int argc, char **argv)
242{
John Beppuf3e59041999-12-22 22:24:52 +0000243 int i;
244 char opt;
245 List list;
246 Line *l;
John Beppuee512a31999-12-23 00:02:49 +0000247 Compare *compare;
John Beppuc0ca4731999-12-21 20:00:35 +0000248
John Beppuee512a31999-12-23 00:02:49 +0000249 /* init */
250 compare = compare_ascii;
251 list_init(&list);
John Beppuc0ca4731999-12-21 20:00:35 +0000252
253 /* parse argv[] */
254 for (i = 1; i < argc; i++) {
255 if (argv[i][0] == '-') {
256 opt = argv[i][1];
257 switch (opt) {
John Beppuee512a31999-12-23 00:02:49 +0000258 case 'g':
John Beppu00417a31999-12-23 22:46:10 +0000259 /* what's the diff between -g && -n? */
260 compare = compare_numeric;
John Beppuee512a31999-12-23 00:02:49 +0000261 break;
John Beppuc0ca4731999-12-21 20:00:35 +0000262 case 'h':
263 usage(sort_usage);
264 break;
John Beppu00417a31999-12-23 22:46:10 +0000265 case 'n':
266 /* what's the diff between -g && -n? */
267 compare = compare_numeric;
268 break;
269 case 'r':
270 /* reverse */
271 break;
John Beppuc0ca4731999-12-21 20:00:35 +0000272 default:
273 fprintf(stderr, "sort: invalid option -- %c\n", opt);
274 usage(sort_usage);
275 }
276 } else {
277 break;
278 }
279 }
280
John Beppu00417a31999-12-23 22:46:10 +0000281 /* this could be factored better */
282
283 /* work w/ stdin */
John Beppuc0ca4731999-12-21 20:00:35 +0000284 if (i >= argc) {
John Beppuf3e59041999-12-22 22:24:52 +0000285 while ( (l = line_newFromFile(stdin))) {
286 list_insert(&list, l);
287 }
John Beppuee512a31999-12-23 00:02:49 +0000288 list_sort(&list, compare);
John Beppuf3e59041999-12-22 22:24:52 +0000289 list_writeToFile(&list, stdout);
290 list_release(&list);
John Beppu00417a31999-12-23 22:46:10 +0000291
292 /* work w/ what's left in argv[] */
John Beppuc0ca4731999-12-21 20:00:35 +0000293 } else {
John Beppu00417a31999-12-23 22:46:10 +0000294 FILE *src;
295
John Beppuc0ca4731999-12-21 20:00:35 +0000296 for ( ; i < argc; i++) {
John Beppu00417a31999-12-23 22:46:10 +0000297 src = fopen(argv[i], "r");
298 if (src == NULL) { break; }
299 while ( (l = line_newFromFile(src))) {
300 list_insert(&list, l);
301 }
302 fclose(src);
John Beppuc0ca4731999-12-21 20:00:35 +0000303 }
John Beppu00417a31999-12-23 22:46:10 +0000304 list_sort(&list, compare);
305 list_writeToFile(&list, stdout);
306 list_release(&list);
John Beppuc0ca4731999-12-21 20:00:35 +0000307 }
308
309 exit(0);
310}
311
John Beppu00417a31999-12-23 22:46:10 +0000312/* $Id: sort.c,v 1.8 1999/12/23 22:46:10 beppu Exp $ */