summaryrefslogtreecommitdiffstats
path: root/funtools/funtest/group.calc
blob: ef5543fdf694ab0c50bfb87ad2b07652c05ede09 (plain)
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