OpenCores
URL https://opencores.org/ocsvn/or1k/or1k/trunk

Subversion Repositories or1k

[/] [or1k/] [tags/] [start/] [insight/] [tix/] [generic/] [tixGrSort.c] - Blame information for rev 1765

Details | Compare with Previous | View Log

Line No. Rev Author Line
1 578 markom
/*
2
 * tixGrSel.c --
3
 *
4
 *      This module handles the sorting of the Grid widget.
5
 *
6
 * Copyright (c) 1996, Expert Interface Technologies
7
 *
8
 * See the file "license.terms" for information on usage and redistribution
9
 * of this file, and for a DISCLAIMER OF ALL WARRANTIES.
10
 *
11
 */
12
 
13
#include <tixPort.h>
14
#include <tixInt.h>
15
#include <tixGrid.h>
16
 
17
/*
18
 * The variables below are used to implement the "lsort" command.
19
 * Unfortunately, this use of static variables prevents "lsort"
20
 * from being thread-safe, but there's no alternative given the
21
 * current implementation of qsort.  In a threaded environment
22
 * these variables should be made thread-local if possible, or else
23
 * "lsort" needs internal mutual exclusion.
24
 */
25
 
26
static Tcl_Interp *sortInterp = NULL;   /* Interpreter for "lsort" command.
27
                                         * NULL means no lsort is active. */
28
static enum {ASCII, INTEGER, REAL, COMMAND} sortMode;
29
                                        /* Mode for sorting:compare as strings,
30
                                         * compare as numbers, or call
31
                                         * user-defined command for
32
                                         * comparison. */
33
static Tcl_DString sortCmd;             /* Holds command if mode is COMMAND.
34
                                         * pre-initialized to hold base of
35
                                         * command. */
36
static int sortIncreasing;              /* 0 means sort in decreasing order,
37
                                         * 1 means increasing order. */
38
static int sortCode;                    /* Anything other than TCL_OK means a
39
                                         * problem occurred while sorting; this
40
                                         * executing a comparison command, so
41
                                         * the sort was aborted. */
42
 
43
/*
44
 * Forward declarations for procedures defined in this file:
45
 */
46
 
47
EXTERN TIX_DECLARE_SUBCMD(Tix_GrSort);
48
 
49
static int              SortCompareProc _ANSI_ARGS_((CONST VOID *first,
50
                            CONST VOID *second));
51
char *                  Tix_GrGetCellText _ANSI_ARGS_((WidgetPtr wPtr,
52
                            int x, int y));
53
Tix_GrSortItem *        Tix_GrGetSortItems _ANSI_ARGS_((WidgetPtr wPtr,
54
                            int axis, int start, int end, int sortKeyIndex));
55
void                    Tix_GrFreeSortItems _ANSI_ARGS_((WidgetPtr wPtr,
56
                            Tix_GrSortItem * items, int numItems));
57
 
58
 
59
/*
60
 *----------------------------------------------------------------------
61
 *
62
 * Tcl_LsortCmd --
63
 *
64
 *      This procedure is invoked to process the "lsort" Tcl command.
65
 *      See the user documentation for details on what it does.
66
 *
67
 * Results:
68
 *      A standard Tcl result.
69
 *
70
 * Side effects:
71
 *      See the user documentation.
72
 *
73
 *----------------------------------------------------------------------
74
 */
75
 
76
        /* ARGSUSED */
77
 
78
char *
79
Tix_GrGetCellText(wPtr, x, y)
80
    WidgetPtr wPtr;
81
    int x;
82
    int y;
83
{
84
    TixGrEntry* chPtr;
85
 
86
    if ((chPtr = (TixGrEntry*) TixGridDataFindEntry(wPtr->dataSet, x, y))) {
87
        switch (Tix_DItemType(chPtr->iPtr)) {
88
          case TIX_DITEM_TEXT:
89
            return chPtr->iPtr->text.text;
90
          case TIX_DITEM_IMAGETEXT:
91
            return chPtr->iPtr->imagetext.text;
92
          default:
93
            return NULL;
94
        }
95
    } else {
96
        return NULL;
97
    }
98
}
99
 
100
Tix_GrSortItem *
101
Tix_GrGetSortItems(wPtr, axis, start, end, sortKeyIndex)
102
    WidgetPtr wPtr;
103
    int axis;
104
    int start;
105
    int end;
106
    int sortKeyIndex;
107
{
108
    int i, k, numItems;
109
    Tix_GrSortItem *items;
110
 
111
    if (end <= start) {
112
        /* sanity check: no need to sort */
113
        return (Tix_GrSortItem *) NULL;
114
    }
115
 
116
    numItems = end-start+1;
117
    items = (Tix_GrSortItem *)ckalloc(sizeof(Tix_GrSortItem) * numItems);
118
 
119
    for (k=0,i=start; i<=end; i++, k++) {
120
        items[k].index = i;
121
        if (axis == 0) {
122
            items[k].data = Tix_GrGetCellText(wPtr, i, sortKeyIndex);
123
        } else {
124
            items[k].data = Tix_GrGetCellText(wPtr, sortKeyIndex, i);
125
        }
126
    }
127
 
128
    return items;
129
}
130
 
131
 
132
void
133
Tix_GrFreeSortItems(wPtr, items, numItems)
134
    WidgetPtr wPtr;
135
    Tix_GrSortItem * items;
136
    int numItems;
137
{
138
    ckfree((char*)items);
139
}
140
 
141
int
142
Tix_GrSort(clientData, interp, argc, argv)
143
    ClientData clientData;
144
    Tcl_Interp *interp;         /* Current interpreter. */
145
    int argc;                   /* Number of arguments. */
146
    char **argv;                /* Argument strings. */
147
{
148
    WidgetPtr wPtr = (WidgetPtr) clientData;
149
    int i, axis, otherAxis, start, end;
150
    size_t len;
151
    Tix_GrSortItem *items = NULL;
152
    int numItems;
153
    char *command = NULL;               /* Initialization needed only to
154
                                         * prevent compiler warning. */
155
    int sortKeyIndex;
156
    int gridSize[2];
157
 
158
    /*-------------------------------------------------------------------
159
     *                  Argument parsing
160
     *-------------------------------------------------------------------
161
     */
162
    if (sortInterp != NULL) {
163
        interp->result = "can't invoke the tixGrid sort command recursively";
164
        return TCL_ERROR;
165
    }
166
 
167
    /* Figure out the sorting dimension
168
     */
169
    len = strlen(argv[0]);
170
    if (strncmp(argv[0], "rows", len)==0) {
171
        axis = 1;
172
        otherAxis = 0;
173
    } else if (strncmp(argv[0], "column", len)==0) {
174
        axis = 0;
175
        otherAxis = 1;
176
    } else {
177
        Tcl_AppendResult(interp, "wrong dimension \"", argv[0],
178
            "\", should be row or column",  (char *) NULL);
179
        return TCL_ERROR;
180
    }
181
 
182
    /* get the start and end index
183
     */
184
    if (axis == 0) {
185
        if (TixGridDataGetIndex(interp, wPtr, argv[1], NULL, &start, NULL)
186
                !=TCL_OK) {
187
            return TCL_ERROR;
188
        }
189
        if (TixGridDataGetIndex(interp, wPtr, argv[2], NULL, &end, NULL)
190
                !=TCL_OK) {
191
            return TCL_ERROR;
192
        }
193
    } else {
194
        if (TixGridDataGetIndex(interp, wPtr, NULL, argv[1], NULL, &start)
195
                !=TCL_OK) {
196
            return TCL_ERROR;
197
        }
198
        if (TixGridDataGetIndex(interp, wPtr, NULL, argv[2], NULL, &end)
199
                !=TCL_OK) {
200
            return TCL_ERROR;
201
        }
202
    }
203
 
204
    /* Check the range
205
     */
206
    TixGridDataGetGridSize(wPtr->dataSet, &gridSize[0], &gridSize[1]);
207
    if (start > end) {
208
        int tmp = start;
209
        start = end;
210
        end = tmp;
211
    }
212
    if (start >= gridSize[axis]) {
213
        /* no need to sort */
214
        return TCL_OK;
215
    }
216
    if (end == start) {
217
        /* no need to sort */
218
        return TCL_OK;
219
    }
220
 
221
    /* get the options
222
     */
223
    if ((argc-3) %2 != 0) {
224
        Tcl_AppendResult(interp, "value for \"", argv[argc-1],
225
                "\" missing", NULL);
226
        return TCL_ERROR;
227
    }
228
    sortInterp = interp;
229
    sortMode = ASCII;
230
    sortIncreasing = 1;
231
    sortCode = TCL_OK;
232
    sortKeyIndex = wPtr->hdrSize[otherAxis];    /* by default, use the first
233
                                                 * scrollable item as the key
234
                                                 */
235
    for (i=3; i<argc; i+=2) {
236
        len = strlen(argv[i]);
237
        if (strncmp(argv[i], "-type", len) == 0) {
238
            if (strcmp(argv[i+1], "ascii") == 0) {
239
                sortMode = ASCII;
240
            } else if (strcmp(argv[i+1], "integer") == 0) {
241
                sortMode = INTEGER;
242
            } else if (strcmp(argv[i+1], "real") == 0) {
243
                sortMode = REAL;
244
            } else {
245
                Tcl_AppendResult(interp, "wrong type \"", argv[i+1],
246
                    "\": must be ascii, integer or real", (char *) NULL);
247
                sortCode = TCL_ERROR;
248
                goto done;
249
            }
250
        }
251
        else if (strncmp(argv[i], "-order", len) == 0) {
252
            if (strcmp(argv[i+1], "increasing") == 0) {
253
                sortIncreasing = 1;
254
            } else if (strcmp(argv[i+1], "decreasing") == 0) {
255
                sortIncreasing = 0;
256
            } else {
257
                Tcl_AppendResult(interp, "wrong order \"", argv[i+1],
258
                    "\": must be increasing or decreasing", (char *) NULL);
259
                sortCode = TCL_ERROR;
260
                goto done;
261
            }
262
        }
263
        else if (strncmp(argv[i], "-key", len) == 0) {
264
            if (axis == 0) {
265
                /* sort columns: the key is a column index (1) */
266
                if (TixGridDataGetIndex(interp, wPtr, NULL, argv[i+1], NULL,
267
                        &sortKeyIndex) !=TCL_OK) {
268
                    sortCode = TCL_ERROR;
269
                    goto done;
270
                }
271
            } else {
272
                /* sort rows: the key is a row index (0)*/
273
                if (TixGridDataGetIndex(interp, wPtr, argv[i+1], NULL,
274
                        &sortKeyIndex, NULL) !=TCL_OK) {
275
                    sortCode = TCL_ERROR;
276
                    goto done;
277
                }
278
            }
279
        }
280
        else if (strncmp(argv[i], "-command", len) == 0) {
281
            sortMode = COMMAND;
282
            command = argv[i+1];
283
        }
284
        else {
285
            Tcl_AppendResult(interp, "wrong option \"", argv[i],
286
                "\": must be -command, -key, -order or -type", (char *) NULL);
287
            sortCode = TCL_ERROR;
288
            goto done;
289
        }
290
    }
291
    if (sortMode == COMMAND) {
292
        Tcl_DStringInit(&sortCmd);
293
        Tcl_DStringAppend(&sortCmd, command, -1);
294
    }
295
 
296
    /*------------------------------------------------------------------
297
     *          SORTING
298
     *------------------------------------------------------------------
299
     */
300
    /* prepare the array to be sorted */
301
    numItems = end - start + 1;
302
    items = Tix_GrGetSortItems(wPtr, axis, start, end, sortKeyIndex);
303
 
304
    if (items != NULL) {
305
        int sizeChanged;
306
 
307
        qsort((VOID *)items, (size_t)numItems, sizeof(Tix_GrSortItem),
308
            SortCompareProc);
309
 
310
        for (i=0; i<numItems; i++) {
311
            printf("%d\n", items[i].index);
312
        }
313
        sizeChanged = TixGridDataUpdateSort(wPtr->dataSet, axis, start, end,
314
            items);
315
        if (sizeChanged) {
316
            Tix_GrDoWhenIdle(wPtr, TIX_GR_RESIZE);
317
        } else {
318
            wPtr->toResetRB = 1;
319
            Tix_GrDoWhenIdle(wPtr, TIX_GR_REDRAW);
320
        }
321
 
322
        Tix_GrFreeSortItems(wPtr, items, numItems);
323
    }
324
 
325
    /* Done */
326
    if (sortCode == TCL_OK) {
327
        Tcl_ResetResult(interp);
328
    }
329
    if (sortMode == COMMAND) {
330
        Tcl_DStringFree(&sortCmd);
331
    }
332
 
333
  done:
334
    sortInterp = NULL;
335
    return sortCode;
336
}
337
 
338
/*
339
 *----------------------------------------------------------------------
340
 *
341
 * SortCompareProc --
342
 *
343
 *      This procedure is invoked by qsort to determine the proper
344
 *      ordering between two elements.
345
 *
346
 * Results:
347
 *      < 0 means first is "smaller" than "second", > 0 means "first"
348
 *      is larger than "second", and 0 means they should be treated
349
 *      as equal.
350
 *
351
 * Side effects:
352
 *      None, unless a user-defined comparison command does something
353
 *      weird.
354
 *
355
 *----------------------------------------------------------------------
356
 */
357
 
358
static int
359
SortCompareProc(first, second)
360
    CONST VOID *first, *second;         /* Elements to be compared. */
361
{
362
    int order;
363
    char *firstString  = ((Tix_GrSortItem*)first )->data;
364
    char *secondString = ((Tix_GrSortItem*)second)->data;
365
 
366
    order = 0;
367
    if (sortCode != TCL_OK) {
368
        /*
369
         * Once an error has occurred, skip any future comparisons
370
         * so as to preserve the error message in sortInterp->result.
371
         */
372
 
373
        return order;
374
    }
375
    if (firstString == NULL && secondString == NULL) {
376
        /* equal */
377
        return order;
378
    }
379
    if (secondString == NULL) {
380
        /* first larger than second */
381
        order = 1;
382
        goto done;
383
    }
384
    if (firstString == NULL) {
385
        order = -1;
386
        goto done;
387
    }
388
 
389
    if (sortMode == ASCII) {
390
        order = strcmp(firstString, secondString);
391
    } else if (sortMode == INTEGER) {
392
        int a, b;
393
 
394
        if ((Tcl_GetInt(sortInterp, firstString, &a) != TCL_OK)
395
                || (Tcl_GetInt(sortInterp, secondString, &b) != TCL_OK)) {
396
            Tcl_AddErrorInfo(sortInterp,
397
                    "\n    (converting list element from string to integer)");
398
            sortCode = TCL_ERROR;
399
            return order;
400
        }
401
        if (a > b) {
402
            order = 1;
403
        } else if (b > a) {
404
            order = -1;
405
        }
406
    } else if (sortMode == REAL) {
407
        double a, b;
408
 
409
        if ((Tcl_GetDouble(sortInterp, firstString, &a) != TCL_OK)
410
                || (Tcl_GetDouble(sortInterp, secondString, &b) != TCL_OK)) {
411
            Tcl_AddErrorInfo(sortInterp,
412
                    "\n    (converting list element from string to real)");
413
            sortCode = TCL_ERROR;
414
            return order;
415
        }
416
        if (a > b) {
417
            order = 1;
418
        } else if (b > a) {
419
            order = -1;
420
        }
421
    } else {
422
        int oldLength;
423
        char *end;
424
 
425
        /*
426
         * Generate and evaluate a command to determine which string comes
427
         * first.
428
         */
429
 
430
        oldLength = Tcl_DStringLength(&sortCmd);
431
        Tcl_DStringAppendElement(&sortCmd, firstString);
432
        Tcl_DStringAppendElement(&sortCmd, secondString);
433
        sortCode = Tcl_Eval(sortInterp, Tcl_DStringValue(&sortCmd));
434
        Tcl_DStringTrunc(&sortCmd, oldLength);
435
        if (sortCode != TCL_OK) {
436
            Tcl_AddErrorInfo(sortInterp,
437
                    "\n    (user-defined comparison command)");
438
            return order;
439
        }
440
 
441
        /*
442
         * Parse the result of the command.
443
         */
444
 
445
        order = strtol(sortInterp->result, &end, 0);
446
        if ((end == sortInterp->result) || (*end != 0)) {
447
            Tcl_ResetResult(sortInterp);
448
            Tcl_AppendResult(sortInterp,
449
                    "comparison command returned non-numeric result",
450
                    (char *) NULL);
451
            sortCode = TCL_ERROR;
452
            return order;
453
        }
454
    }
455
 
456
done:
457
    if (!sortIncreasing) {
458
        order = -order;
459
    }
460
    return order;
461
}

powered by: WebSVN 2.1.0

© copyright 1999-2024 OpenCores.org, equivalent to Oliscience, all rights reserved. OpenCores®, registered trademark.