1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
|
/* globals go before main */
global
#define SAVEINC 100
/* not available before 1.3.0b25 */
#define I __i
/* our save record contains a funcalc row record and a place for raw data */
typedef struct savestruct{
RowRec row;
char *raw;
} *Save, SaveRec;
/* qsort comparison routine -- reverse order of x */
static int _Cmp(const void *s1, const void *s2)
{
Save f1 = (Save)s1;
Save f2 = (Save)s2;
/* order flag */
if( f1->row.x < f2->row.x )
return -1;
if( f1->row.x > f2->row.x )
return 1;
else
return 0;
}
/* this is the heart of the algorithm */
static void ProcessRows(Fun fun, Fun ofun, Save save, int nsave)
{
int i;
/* sort rows */
qsort(save, nsave, sizeof(SaveRec), _Cmp);
/* output rows in new order */
for(i=0; i<nsave; i++){
/* re-associate raw data with this row */
FunInfoPut(fun, FUN_RAWBUF, &save[i].raw, 0);
/* write the row */
FunTableRowPut(ofun, &save[i].row, 1, 0, NULL);
}
}
end
/* locals go immediately after local variables in main */
local
char *cptr=NULL;
char *rptr=NULL;
int i=0;
int group=0;
int rawsize=0;
int lastkey=0;
int maxsave=0;
int nsave=0;
Save save=NULL;
end
/* execute this before we enter inner loop */
before
/* get size of raw input record */
FunInfoGet(fun, FUN_RAWSIZE, &rawsize, 0);
end
/* MAIN ROW PROCESSING LOOP */
/* first time through, just seed last key */
if( NROW == 0 ) lastkey=cur->key;
/* save raw data for this set of rows */
FunInfoGet(fun, FUN_RAWBUF, &rptr, 0);
/* if this key starts a new group, process and output previous group */
if( cur->key != lastkey ){
/* process current group */
ProcessRows(fun, ofun, save, nsave);
/* restore the current row pointers so we can process the next row */
FunInfoPut(fun, FUN_RAWBUF, &rptr, 0);
/* reset number of keys in this group */
nsave = 0;
/* got another group */
group++;
}
/* user manipulation */
/* set values of a new column */
cur->group:I = group;
/* manipulate one of the user columns */
cur->x = -cur->x;
/* save this row ... first make sure we have enough space */
if( nsave >= maxsave ){
maxsave += SAVEINC;
if( !save )
save = xmalloc(maxsave*sizeof(SaveRec));
else
save = xrealloc(save, maxsave*sizeof(SaveRec));
/* clear what we just alloc'ed (wish realloc() would do this! */
memset(save+((maxsave-SAVEINC)*sizeof(SaveRec)), 0, SAVEINC*sizeof(SaveRec));
}
/* save the user part of this row */
memcpy(&(save[nsave].row), cur, sizeof(RowRec));
/* might have to allocate space for raw */
if( !save[nsave].raw ) save[nsave].raw = xmalloc(rawsize);
/* save raw data for this row */
memcpy(save[nsave].raw, rptr+(I*rawsize), rawsize);
/* saved another key in this group */
nsave++;
/* this key becomes last key */
lastkey = cur->key;
/* prevent funcalc from writing out the current record */
continue;
/* END OF INNER LOOP */
/* after we leave inner loop */
after
/* process rows in last group */
ProcessRows(fun, ofun, save, nsave);
/* restore raw buf pointer so FunClose can free it properly */
FunInfoPut(fun, FUN_RAWBUF, &rptr, 0);
/* clean up saved data */
for(i=0; i<maxsave; i++){
if( save[i].raw ) xfree(save[i].raw);
}
if( save ) xfree(save);
end
|