Hint added.
[AROS.git] / workbench / c / Sort.c
blobf10bcdeda2641a120eb23c858414de0c19c67cd5
1 /*
2 Copyright © 1995-2014, The AROS Development Team. All rights reserved.
3 $Id$
5 Desc: Sorts the contents of a file
6 Lang: English
7 */
8 /*****************************************************************************
10 NAME
12 Sort
14 SYNOPSIS
16 FROM/A,TO/A,COLSTART/K,CASE/S,NUMERIC/S
18 LOCATION
22 FUNCTION
24 Sorts the contents of a text file
26 INPUTS
28 FROM -- file to read from
29 TO -- file to output to
30 COLSTART -- column at which the comparison begins
31 CASE -- sort is case sensitive. Uppercase items are output first
32 NUMERIC -- lines are interpreted as numbers
34 RESULT
36 EXAMPLE
38 BUGS
40 SEE ALSO
42 INTERNALS
44 HISTORY
46 ******************************************************************************/
48 #include <clib/macros.h>
49 #include <exec/memory.h>
50 #include <exec/types.h>
51 #include <dos/dos.h>
52 #include <dos/exall.h>
53 #include <proto/dos.h>
54 #include <proto/exec.h>
55 #include <proto/utility.h>
56 #include <proto/locale.h>
57 #include <libraries/locale.h>
58 #include <utility/tagitem.h>
60 #define DEBUG 0
61 #include <aros/debug.h>
63 #include <string.h>
65 #define TEMPLATE "FROM/A,TO/A,COLSTART/K,CASE/S,NUMERIC/S"
67 #define ARG_FROM 0
68 #define ARG_TO 1
69 #define ARG_COLSTART 2
70 #define ARG_CASE 3
71 #define ARG_NUMERIC 4
73 #define ARG_NUM 5
75 const TEXT version[] = "$VER: Sort 41.2 (3.4.2014)";
77 struct sorted_data
79 struct sorted_data * next;
80 UBYTE * data;
81 ULONG len; // length of line including '\n'.
84 struct Locale * locale;
86 int compare(struct sorted_data * sd1,
87 struct sorted_data * sd2,
88 ULONG col,
89 BOOL case_on)
91 ULONG len = MIN(sd1->len, sd2->len);
93 /* FIXME: It seems like StrnCmp of locale does not work. */
94 #if 1
95 LONG retval = 0;
97 if (case_on)
99 int i = col;
101 while (i < len)
103 BOOL a,b;
104 a = IsUpper(locale,(ULONG)*(sd1->data+col+i));
105 b = IsUpper(locale,(ULONG)*(sd2->data+col+i));
107 if (a == b)
109 if (0 != (retval = StrnCmp(locale,
110 sd1->data+col,
111 sd2->data+col,
113 SC_COLLATE2)))
114 break;
116 else
118 retval = b - a;
119 break;
122 i++;
125 else
128 retval=StrnCmp(locale,
129 sd1->data+col,
130 sd2->data+col,
131 len,
132 SC_COLLATE2);
134 if (0 == retval)
136 if (sd1->len < sd2->len)
137 retval = -100;
138 else
139 retval = +100;
143 return retval;
145 #else
146 int i = col;
147 char * str1 = sd1->data;
148 char * str2 = sd2->data;
150 while (i < len)
152 if (str1[i] != str2[i])
153 return (int)(str1[i] - str2[i]);
155 i++;
158 return (int)sd1->len - (int)sd2->len;
159 #endif
163 struct sorted_data * sort(UBYTE * data,
164 ULONG data_len,
165 STRPTR colstart,
166 BOOL case_on,
167 BOOL is_numeric)
169 ULONG pos = 0;
170 ULONG col = 0;
171 struct sorted_data * first = NULL;
172 struct sorted_data * cur = NULL;
173 struct sorted_data * tooshort = NULL;
174 struct sorted_data * tooshort_last = NULL;
176 if (colstart)
178 while (*colstart >= '0' && *colstart <= '9')
179 col = col * 10 + *colstart++ - '0';
180 if (col > 0)
181 col-=1;
184 while (pos < data_len)
186 ULONG begin = pos;
187 ULONG len;
189 while (pos < data_len && data[pos] != 0x0a)
190 pos++;
192 if (data[pos] == 0x0a || pos == data_len)
193 len = pos++ - begin;
194 else
195 len = ++pos - begin;
197 cur = AllocMem(sizeof(struct sorted_data), MEMF_ANY|MEMF_CLEAR);
199 if (cur)
201 cur->data = data + begin;
202 cur->len = len;
204 if (len > col)
207 ** Insert it into the list of sorted lines
209 if (NULL != first)
212 ** To be first in the list?
214 if (compare(cur, first, col, case_on) < 0)
216 cur->next = first;
217 first = cur;
219 else
221 struct sorted_data * _cur = first;
223 while (1)
226 ** Insert it after the current one and before the
227 ** next one?
229 if (NULL == _cur->next)
231 _cur->next = cur;
232 break;
234 if (compare(cur, _cur->next, col, case_on) < 0)
236 cur -> next = _cur->next;
237 _cur-> next = cur;
238 break;
241 _cur = _cur->next;
244 } /* if (NULL != first) */
245 else
246 first = cur;
248 else
250 /* this line is too short to sort it in */
251 if (NULL == tooshort)
253 tooshort = cur;
254 tooshort_last = cur;
256 else
258 tooshort_last->next = cur;
259 tooshort_last = cur;
262 } /* if (cur) */
266 if (NULL != tooshort)
268 tooshort_last->next = first;
269 first = tooshort;
272 return first;
276 LONG write_data(struct sorted_data * start, BPTR file_out)
278 BOOL write = TRUE;
279 LONG error = 0;
280 LONG count;
282 while (start)
284 struct sorted_data * next = start->next;
286 if (write)
288 count = Write(file_out, start->data, start->len);
289 if (count != -1 && start->data[start->len-1] != 0x0a)
290 count = Write(file_out, "\n", 1);
291 if (count == -1)
293 error = IoErr();
294 write = FALSE;
298 FreeMem(start, sizeof(struct sorted_data));
299 start = next;
302 return error;
305 int __nocommandline;
307 int main (void)
309 IPTR args[ARG_NUM] = { (IPTR) NULL, (IPTR) NULL, (IPTR) NULL, FALSE, FALSE};
310 struct RDArgs *rda;
311 LONG result = RETURN_OK;
312 LONG error = 0;
314 locale = OpenLocale(NULL);
315 if (!locale)
317 PutStr("Could not open locale!\n");
318 return RETURN_FAIL;
321 rda = ReadArgs(TEMPLATE, args, NULL);
322 if (rda)
324 BPTR lock_in;
325 lock_in = Lock((STRPTR)args[ARG_FROM], ACCESS_READ);
327 if (lock_in)
329 BPTR file_out = Open((STRPTR)args[ARG_TO], MODE_NEWFILE);
330 if (file_out == BNULL)
331 error = IoErr();
332 struct FileInfoBlock *fib = AllocDosObject(DOS_FIB, NULL);
333 if (fib == NULL)
334 error = IoErr();
336 if (error == 0)
338 UBYTE * data = NULL;
339 BOOL success = Examine(lock_in, fib);
342 ** Read the input file into memory
344 if (fib->fib_Size && success)
345 data = AllocVec(fib->fib_Size, MEMF_ANY);
347 if (data)
349 BPTR in;
350 if ((in = OpenFromLock(lock_in))) {
351 ULONG read = Read(in, data, fib->fib_Size);
353 if (-1 != read)
355 struct sorted_data * sd;
356 sd = sort(data,
357 fib->fib_Size,
358 (STRPTR)args[ARG_COLSTART],
359 (BOOL)args[ARG_CASE],
360 (BOOL)args[ARG_NUMERIC]);
362 error = write_data(sd, file_out);
364 Close(in);
365 lock_in = BNULL;
367 FreeVec(data);
369 else
370 error = IoErr();
372 Close(file_out);
374 FreeDosObject(DOS_FIB, fib);
375 if (lock_in)
376 UnLock(lock_in);
378 else
379 error = IoErr();
380 FreeArgs(rda);
382 else
383 error = IoErr();
385 if (error)
387 PrintFault(error, "Sort");
388 result = RETURN_FAIL;
391 return result;