diff options
Diffstat (limited to 'sort.c')
-rw-r--r-- | sort.c | 385 |
1 files changed, 193 insertions, 192 deletions
@@ -1,3 +1,4 @@ | |||
1 | /* vi: set sw=4 ts=4: */ | ||
1 | /* | 2 | /* |
2 | * Mini sort implementation for busybox | 3 | * Mini sort implementation for busybox |
3 | * | 4 | * |
@@ -28,29 +29,27 @@ | |||
28 | #include <stdio.h> | 29 | #include <stdio.h> |
29 | #include <errno.h> | 30 | #include <errno.h> |
30 | 31 | ||
31 | static const char sort_usage[] = | 32 | static const char sort_usage[] = "sort [OPTION]... [FILE]...\n\n"; |
32 | "sort [OPTION]... [FILE]...\n\n" | ||
33 | ; | ||
34 | 33 | ||
35 | /* typedefs _______________________________________________________________ */ | 34 | /* typedefs _______________________________________________________________ */ |
36 | 35 | ||
37 | /* line node */ | 36 | /* line node */ |
38 | typedef struct Line { | 37 | typedef struct Line { |
39 | char *data; /* line data */ | 38 | char *data; /* line data */ |
40 | struct Line *next; /* pointer to next line node */ | 39 | struct Line *next; /* pointer to next line node */ |
41 | } Line; | 40 | } Line; |
42 | 41 | ||
43 | /* singly-linked list of lines */ | 42 | /* singly-linked list of lines */ |
44 | typedef struct { | 43 | typedef struct { |
45 | int len; /* number of Lines */ | 44 | int len; /* number of Lines */ |
46 | Line **sorted; /* array fed to qsort */ | 45 | Line **sorted; /* array fed to qsort */ |
47 | 46 | ||
48 | Line *head; /* head of List */ | 47 | Line *head; /* head of List */ |
49 | Line *current; /* current Line */ | 48 | Line *current; /* current Line */ |
50 | } List; | 49 | } List; |
51 | 50 | ||
52 | /* comparison function */ | 51 | /* comparison function */ |
53 | typedef int (Compare)(const void *, const void *); | 52 | typedef int (Compare) (const void *, const void *); |
54 | 53 | ||
55 | 54 | ||
56 | /* methods ________________________________________________________________ */ | 55 | /* methods ________________________________________________________________ */ |
@@ -58,175 +57,176 @@ typedef int (Compare)(const void *, const void *); | |||
58 | static const int max = 1024; | 57 | static const int max = 1024; |
59 | 58 | ||
60 | /* mallocate Line */ | 59 | /* mallocate Line */ |
61 | static Line * | 60 | static Line *line_alloc() |
62 | line_alloc() | ||
63 | { | 61 | { |
64 | Line *self; | 62 | Line *self; |
65 | self = malloc(1 * sizeof(Line)); | 63 | |
66 | return self; | 64 | self = malloc(1 * sizeof(Line)); |
65 | return self; | ||
67 | } | 66 | } |
68 | 67 | ||
69 | /* Initialize Line with string */ | 68 | /* Initialize Line with string */ |
70 | static Line * | 69 | static Line *line_init(Line * self, const char *string) |
71 | line_init(Line *self, const char *string) | ||
72 | { | 70 | { |
73 | self->data = malloc((strlen(string) + 1) * sizeof(char)); | 71 | self->data = malloc((strlen(string) + 1) * sizeof(char)); |
74 | if (self->data == NULL) { return NULL; } | 72 | |
75 | strcpy(self->data, string); | 73 | if (self->data == NULL) { |
76 | self->next = NULL; | 74 | return NULL; |
77 | return self; | 75 | } |
76 | strcpy(self->data, string); | ||
77 | self->next = NULL; | ||
78 | return self; | ||
78 | } | 79 | } |
79 | 80 | ||
80 | /* Construct Line from FILE* */ | 81 | /* Construct Line from FILE* */ |
81 | static Line * | 82 | static Line *line_newFromFile(FILE * src) |
82 | line_newFromFile(FILE *src) | ||
83 | { | 83 | { |
84 | char buffer[max]; | 84 | char buffer[max]; |
85 | Line *self; | 85 | Line *self; |
86 | 86 | ||
87 | if (fgets(buffer, max, src)) { | 87 | if (fgets(buffer, max, src)) { |
88 | self = line_alloc(); | 88 | self = line_alloc(); |
89 | if (self == NULL) { return NULL; } | 89 | if (self == NULL) { |
90 | line_init(self, buffer); | 90 | return NULL; |
91 | return self; | 91 | } |
92 | } | 92 | line_init(self, buffer); |
93 | return NULL; | 93 | return self; |
94 | } | ||
95 | return NULL; | ||
94 | } | 96 | } |
95 | 97 | ||
96 | /* Line destructor */ | 98 | /* Line destructor */ |
97 | static Line * | 99 | static Line *line_release(Line * self) |
98 | line_release(Line *self) | ||
99 | { | 100 | { |
100 | if (self->data) { | 101 | if (self->data) { |
101 | free(self->data); | 102 | free(self->data); |
102 | free(self); | 103 | free(self); |
103 | } | 104 | } |
104 | return self; | 105 | return self; |
105 | } | 106 | } |
106 | 107 | ||
107 | 108 | ||
108 | /* Comparison */ | 109 | /* Comparison */ |
109 | 110 | ||
110 | /* ascii order */ | 111 | /* ascii order */ |
111 | static int | 112 | static int compare_ascii(const void *a, const void *b) |
112 | compare_ascii(const void *a, const void *b) | ||
113 | { | 113 | { |
114 | Line **doh; | 114 | Line **doh; |
115 | Line *x, *y; | 115 | Line *x, *y; |
116 | 116 | ||
117 | doh = (Line **) a; | 117 | doh = (Line **) a; |
118 | x = *doh; | 118 | x = *doh; |
119 | doh = (Line **) b; | 119 | doh = (Line **) b; |
120 | y = *doh; | 120 | y = *doh; |
121 | 121 | ||
122 | // fprintf(stdout, "> %p: %s< %p: %s", x, x->data, y, y->data); | 122 | // fprintf(stdout, "> %p: %s< %p: %s", x, x->data, y, y->data); |
123 | return strcmp(x->data, y->data); | 123 | return strcmp(x->data, y->data); |
124 | } | 124 | } |
125 | 125 | ||
126 | /* numeric order */ | 126 | /* numeric order */ |
127 | static int | 127 | static int compare_numeric(const void *a, const void *b) |
128 | compare_numeric(const void *a, const void *b) | ||
129 | { | 128 | { |
130 | Line **doh; | 129 | Line **doh; |
131 | Line *x, *y; | 130 | Line *x, *y; |
132 | int xint, yint; | 131 | int xint, yint; |
133 | 132 | ||
134 | doh = (Line **) a; | 133 | doh = (Line **) a; |
135 | x = *doh; | 134 | x = *doh; |
136 | doh = (Line **) b; | 135 | doh = (Line **) b; |
137 | y = *doh; | 136 | y = *doh; |
138 | 137 | ||
139 | xint = strtoul(x->data, NULL, 10); | 138 | xint = strtoul(x->data, NULL, 10); |
140 | yint = strtoul(y->data, NULL, 10); | 139 | yint = strtoul(y->data, NULL, 10); |
141 | 140 | ||
142 | return (xint - yint); | 141 | return (xint - yint); |
143 | } | 142 | } |
144 | 143 | ||
145 | 144 | ||
146 | /* List */ | 145 | /* List */ |
147 | 146 | ||
148 | /* */ | 147 | /* */ |
149 | static List * | 148 | static List *list_init(List * self) |
150 | list_init(List *self) | ||
151 | { | 149 | { |
152 | self->len = 0; | 150 | self->len = 0; |
153 | self->sorted = NULL; | 151 | self->sorted = NULL; |
154 | self->head = NULL; | 152 | self->head = NULL; |
155 | self->current = NULL; | 153 | self->current = NULL; |
156 | return self; | 154 | return self; |
157 | } | 155 | } |
158 | 156 | ||
159 | /* for simplicity, the List gains ownership of the line */ | 157 | /* for simplicity, the List gains ownership of the line */ |
160 | static List * | 158 | static List *list_insert(List * self, Line * line) |
161 | list_insert(List *self, Line *line) | ||
162 | { | 159 | { |
163 | if (line == NULL) { return NULL; } | 160 | if (line == NULL) { |
164 | 161 | return NULL; | |
165 | /* first insertion */ | 162 | } |
166 | if (self->head == NULL) { | 163 | |
167 | self->head = line; | 164 | /* first insertion */ |
168 | self->current = line; | 165 | if (self->head == NULL) { |
169 | 166 | self->head = line; | |
170 | /* all subsequent insertions */ | 167 | self->current = line; |
171 | } else { | 168 | |
172 | self->current->next = line; | 169 | /* all subsequent insertions */ |
173 | self->current = line; | 170 | } else { |
174 | } | 171 | self->current->next = line; |
175 | self->len++; | 172 | self->current = line; |
176 | return self; | 173 | } |
174 | self->len++; | ||
175 | return self; | ||
177 | } | 176 | } |
178 | 177 | ||
179 | /* order the list according to compare() */ | 178 | /* order the list according to compare() */ |
180 | static List * | 179 | static List *list_sort(List * self, Compare * compare) |
181 | list_sort(List *self, Compare *compare) | ||
182 | { | 180 | { |
183 | int i; | 181 | int i; |
184 | Line *line; | 182 | Line *line; |
185 | 183 | ||
186 | /* mallocate array of Line*s */ | 184 | /* mallocate array of Line*s */ |
187 | self->sorted = (Line **) malloc(self->len * sizeof(Line*)); | 185 | self->sorted = (Line **) malloc(self->len * sizeof(Line *)); |
188 | if (self->sorted == NULL) { return NULL; } | 186 | if (self->sorted == NULL) { |
189 | 187 | return NULL; | |
190 | /* fill array w/ List's contents */ | 188 | } |
191 | i = 0; | 189 | |
192 | line = self->head; | 190 | /* fill array w/ List's contents */ |
193 | while (line) { | 191 | i = 0; |
194 | self->sorted[i++] = line; | 192 | line = self->head; |
195 | line = line->next; | 193 | while (line) { |
196 | } | 194 | self->sorted[i++] = line; |
197 | 195 | line = line->next; | |
198 | /* apply qsort */ | 196 | } |
199 | qsort(self->sorted, self->len, sizeof(Line*), compare); | 197 | |
200 | return self; | 198 | /* apply qsort */ |
199 | qsort(self->sorted, self->len, sizeof(Line *), compare); | ||
200 | return self; | ||
201 | } | 201 | } |
202 | 202 | ||
203 | /* precondition: list must be sorted */ | 203 | /* precondition: list must be sorted */ |
204 | static List * | 204 | static List *list_writeToFile(List * self, FILE * dst) |
205 | list_writeToFile(List *self, FILE* dst) | ||
206 | { | 205 | { |
207 | int i; | 206 | int i; |
208 | Line **line = self->sorted; | 207 | Line **line = self->sorted; |
209 | 208 | ||
210 | if (self->sorted == NULL) { return NULL; } | 209 | if (self->sorted == NULL) { |
211 | for (i = 0; i < self->len; i++) { | 210 | return NULL; |
212 | fprintf(dst, "%s", line[i]->data); | 211 | } |
213 | } | 212 | for (i = 0; i < self->len; i++) { |
214 | return self; | 213 | fprintf(dst, "%s", line[i]->data); |
214 | } | ||
215 | return self; | ||
215 | } | 216 | } |
216 | 217 | ||
217 | /* deallocate */ | 218 | /* deallocate */ |
218 | static void | 219 | static void list_release(List * self) |
219 | list_release(List *self) | ||
220 | { | 220 | { |
221 | Line *i; | 221 | Line *i; |
222 | Line *die; | 222 | Line *die; |
223 | 223 | ||
224 | i = self->head; | 224 | i = self->head; |
225 | while (i) { | 225 | while (i) { |
226 | die = i; | 226 | die = i; |
227 | i = die->next; | 227 | i = die->next; |
228 | line_release(die); | 228 | line_release(die); |
229 | } | 229 | } |
230 | } | 230 | } |
231 | 231 | ||
232 | 232 | ||
@@ -237,76 +237,77 @@ list_release(List *self) | |||
237 | * and finally print it | 237 | * and finally print it |
238 | */ | 238 | */ |
239 | 239 | ||
240 | int | 240 | int sort_main(int argc, char **argv) |
241 | sort_main(int argc, char **argv) | ||
242 | { | 241 | { |
243 | int i; | 242 | int i; |
244 | char opt; | 243 | char opt; |
245 | List list; | 244 | List list; |
246 | Line *l; | 245 | Line *l; |
247 | Compare *compare; | 246 | Compare *compare; |
248 | 247 | ||
249 | /* init */ | 248 | /* init */ |
250 | compare = compare_ascii; | 249 | compare = compare_ascii; |
251 | list_init(&list); | 250 | list_init(&list); |
252 | 251 | ||
253 | /* parse argv[] */ | 252 | /* parse argv[] */ |
254 | for (i = 1; i < argc; i++) { | 253 | for (i = 1; i < argc; i++) { |
255 | if (argv[i][0] == '-') { | 254 | if (argv[i][0] == '-') { |
256 | opt = argv[i][1]; | 255 | opt = argv[i][1]; |
257 | switch (opt) { | 256 | switch (opt) { |
258 | case 'g': | 257 | case 'g': |
259 | /* what's the diff between -g && -n? */ | 258 | /* what's the diff between -g && -n? */ |
260 | compare = compare_numeric; | 259 | compare = compare_numeric; |
261 | break; | 260 | break; |
262 | case 'h': | 261 | case 'h': |
263 | usage(sort_usage); | 262 | usage(sort_usage); |
264 | break; | 263 | break; |
265 | case 'n': | 264 | case 'n': |
266 | /* what's the diff between -g && -n? */ | 265 | /* what's the diff between -g && -n? */ |
267 | compare = compare_numeric; | 266 | compare = compare_numeric; |
268 | break; | 267 | break; |
269 | case 'r': | 268 | case 'r': |
270 | /* reverse */ | 269 | /* reverse */ |
271 | break; | 270 | break; |
272 | default: | 271 | default: |
273 | fprintf(stderr, "sort: invalid option -- %c\n", opt); | 272 | fprintf(stderr, "sort: invalid option -- %c\n", opt); |
274 | usage(sort_usage); | 273 | usage(sort_usage); |
275 | } | 274 | } |
276 | } else { | 275 | } else { |
277 | break; | 276 | break; |
277 | } | ||
278 | } | 278 | } |
279 | } | ||
280 | 279 | ||
281 | /* this could be factored better */ | 280 | /* this could be factored better */ |
282 | 281 | ||
283 | /* work w/ stdin */ | 282 | /* work w/ stdin */ |
284 | if (i >= argc) { | 283 | if (i >= argc) { |
285 | while ( (l = line_newFromFile(stdin))) { | 284 | while ((l = line_newFromFile(stdin))) { |
286 | list_insert(&list, l); | 285 | list_insert(&list, l); |
287 | } | 286 | } |
288 | list_sort(&list, compare); | 287 | list_sort(&list, compare); |
289 | list_writeToFile(&list, stdout); | 288 | list_writeToFile(&list, stdout); |
290 | list_release(&list); | 289 | list_release(&list); |
291 | 290 | ||
292 | /* work w/ what's left in argv[] */ | 291 | /* work w/ what's left in argv[] */ |
293 | } else { | 292 | } else { |
294 | FILE *src; | 293 | FILE *src; |
295 | 294 | ||
296 | for ( ; i < argc; i++) { | 295 | for (; i < argc; i++) { |
297 | src = fopen(argv[i], "r"); | 296 | src = fopen(argv[i], "r"); |
298 | if (src == NULL) { break; } | 297 | if (src == NULL) { |
299 | while ( (l = line_newFromFile(src))) { | 298 | break; |
300 | list_insert(&list, l); | 299 | } |
301 | } | 300 | while ((l = line_newFromFile(src))) { |
302 | fclose(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); | ||
303 | } | 308 | } |
304 | list_sort(&list, compare); | ||
305 | list_writeToFile(&list, stdout); | ||
306 | list_release(&list); | ||
307 | } | ||
308 | 309 | ||
309 | exit(0); | 310 | exit(0); |
310 | } | 311 | } |
311 | 312 | ||
312 | /* $Id: sort.c,v 1.10 2000/02/07 05:29:42 erik Exp $ */ | 313 | /* $Id: sort.c,v 1.11 2000/02/08 19:58:47 erik Exp $ */ |