summaryrefslogtreecommitdiffstats
path: root/funtools/tabcalc.c
blob: c3e0b4db0280a0509fd96b8e70512c5c97f645db (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
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
/*
 *
 * This program was generated automatically by the funcalc program,
 * by running the tabcalc.c template through the funcalc.l lexical analyzer.
 * On this system, it was (or can be) built a command such as:
 *
 * $COMMAND
 *
 */
#include <stdio.h>
#include <unistd.h>
#include <stdlib.h>
#include <math.h>
#include <string.h>
#include <funtools.h>
#include <word.h>
#include <NaN.h>

extern char *optarg;
extern int optind;

/* define the types of event records we have to handle */
#define REC_CUR		1
#define REC_PREV	2
#define REC_NEXT	4

#define ARGC     __nxarg
#define ARGV(n) ((__xargs && (n>=0) && (n<__nxarg)) ? __xargs[n] : NULL)

#define I __i
#define NROW __nrow
#define WRITE_ROW FunTableRowPut(ofun, (char *)cur, 1, __i, NULL)

/* default number of rows to read at a time */
#define MAXROW 8192
int __maxrow=MAXROW;

/* floating check for equality */
#ifndef feq
#define feq(x,y)	(fabs((double)x-(double)y)<=(double)1.0E-15)
/* avoid divide by zero */
#ifndef div
#define div(a,b) (feq(b,0)?(getnand()):(a/b))
#endif
#endif

typedef struct rowstruct{
$MEMBERS
int __ncol;
} *Row, RowRec;

/* global definitions and init calls go here */
$GLOBAL

/* main program */
int main (int argc, char **argv)
{
  int __c, __i;
  int __get, __got, __total, __rectype, __args;
  int __saved=0;
  int __del=0;
  int __nxarg=0;
  int __ip=0;
  int __nrow=-1;
  int __rawsize=0;
  char *__s;
  char *__cols=NULL;
  char *__argstr=NULL;
  char *__rawsave=NULL;
  char *__rawbuf=NULL;
  char **__xargs=NULL;
  char __tbuf[SZ_LINE];
  Row __rowbuf, __rowrptr, __rowsptr, __roweptr;
  Row cur, prev, next;
  Fun fun, ofun;
  off_t __opos;
  $AUTO
  
  /* local definitions, followed by init calls, go here */
  $LOCAL

  /* exit on gio errors */
  if( !getenv("GERROR")  )
    setgerror(2);

  /* avoid shared library problems by using "process" type for filtering */
  putenv("FILTER_PTYPE=process");

  /* process switch arguments */
  while ((__c = getopt(argc, argv, "a:d")) != -1){
    switch(__c){
    case 'a':
      __argstr = xstrdup(optarg);
      break;
    case 'd':
      __del = 1;
      break;
    }
  }

  /* check for required arguments */
  __args = argc - optind;
  /* make sure we have minimal arguments */
  if( __args < $ARGS ){
    if( $ARGS == 1 )
      fprintf(stderr, "usage: %s iname\n", argv[0]);
    else
      fprintf(stderr, "usage: %s iname oname [cols]\n", argv[0]);
    goto error;
  }

  /* set passed arguments in __xargs array */
  if( __argstr && *__argstr ){
    __xargs = calloc(SZ_LINE, sizeof(char *));
    while( word(__argstr, __tbuf, &__ip) ){
      if( __nxarg >= SZ_LINE ){
	gerror(stderr, "too many args passed via -a\n");
	goto error;
      }
      __xargs[__nxarg++] = xstrdup(__tbuf);
    }
  }

  /* set rectype: determine whether we need prev,next records */
  __rectype=$RECTYPE;

  /* get maxrow,if user-specified */
  if( (__s=(char *)getenv("FUN_MAXROW")) != NULL )
    __maxrow = atoi(__s);
  /* make sure max row is large enough to handle prev, next */
  if( __rectype & (REC_PREV|REC_NEXT) )
    __maxrow = MAX(3,__maxrow);
  else
    __maxrow = MAX(1,__maxrow);
  /* this is what we read each time */
  __get = __maxrow;

  /* open input file */
  if( !(fun = FunOpen(argv[optind+0], "rc", NULL)) ){
      gerror(stderr, "could not FunOpen input file: %s\n", argv[optind+0]);
      goto error;
  }

  /* open the output FITS image, inheriting params from input */
  if( $ARGS > 1 ){
    if( !(ofun = FunOpen(argv[optind+1], "w", fun)) ){
      gerror(stderr, "could not FunOpen output file: %s\n", argv[optind+1]);
      goto error;
    }
  }

  /* select columns */
  FunColumnSelect(fun, sizeof(RowRec), "merge=$MERGE", 
		  $SELECT
		  "$N", "1J", "r", FUN_OFFSET(Row, __ncol),
		  NULL);

  /* activate specified columns -- these will be written to the output file */
  if( __args >= 3 ) __cols = argv[optind+2];
  FunColumnActivate(fun, __cols, NULL);

  /* allocate space for __rowbuf -- we will manage this buffer ourselves */
  /* NB: we need 2 extra rows for prev and next */
  __rowbuf = (Row)xcalloc(__maxrow+2, sizeof(RowRec));

  /* get size of raw data record and allocate a raw record */
  FunInfoGet(fun, FUN_RAWSIZE, &__rawsize, 0);
  __rawsave = (char *)xcalloc(1, __rawsize);

  /*  no record read yet */
  __total = 0;

  /* any user-defined calls before we enter the row loop go here */
  $BEFORE

  /* main loop -- get rows and process */
  while( 1 ){
    if( !(__rectype & (REC_PREV|REC_NEXT)) ){
      /* offset of next record to process */
      __rowsptr = __rowbuf;
      __rowrptr = __rowbuf;
    }
    /* need prev record */
    else if( __rectype & REC_PREV ){
      /* no records yet: read new batch of records into start of __rowbuf */
      if( __total == 0 ){
	__rowsptr = __rowbuf+1;
	__rowrptr = __rowbuf;
      }
      /* read last processed record into start of __rowbuf, process others */
      else{
	if( __rectype & REC_NEXT ){
          memcpy(__rowbuf, __rowrptr+(__got-2), sizeof(RowRec)*2);
          __rowsptr = __rowbuf+1;
	  __rowrptr = __rowbuf+2;
	  /* save raw data for this unprocessed record */
	  FunInfoGet(fun, FUN_RAWBUF, &__rawbuf, 0);
	  memcpy(__rawsave, __rawbuf+((__got-1)*__rawsize), __rawsize);
	}
	else{
          memcpy(__rowbuf, __rowrptr+(__got-1), sizeof(RowRec));
	  __rowsptr = __rowbuf+1;
	  __rowrptr = __rowbuf+1;
	}
      }
    }
    /* if we did not process last record, seek to it now and start there */
    else if( __rectype & REC_NEXT ){
      /* no records yet: read new batch of records into start of __rowbuf */
      if( __total == 0 ){
	__rowsptr = __rowbuf;
	__rowrptr = __rowbuf;
      }
      /* read last processed record into first new record, process others */
      else{
	memcpy(__rowbuf, __rowrptr+(__got-1), sizeof(RowRec));
	__rowsptr = __rowbuf;
	__rowrptr = __rowbuf+1;
	/* save raw data for this unprocessed record */
	FunInfoGet(fun, FUN_RAWBUF, &__rawbuf, 0);
	memcpy(__rawsave, __rawbuf+((__got-1)*__rawsize), __rawsize);
      }
    }

    /* read new rows */
    if( !FunTableRowGet(fun, __rowrptr, __get, NULL, &__got) || !__got )
      break;

    /* last record to process */
    __roweptr = __rowrptr + __got;
    /* if we need access to next record, don't process the last one we read */
    if( __rectype & REC_NEXT ){
      __roweptr--;
    }

    /* make sure there are rows to process */
    if( (__roweptr-__rowsptr) <= 0 ) break;

    /* process all rows */
    for(cur=__rowsptr, __i=__rowsptr-__rowrptr; cur<__roweptr; cur++, __i++){
      /* save raw buffer and switch rawbuf from previous */
      if( __i == -1 ){
	FunInfoGet(fun, FUN_RAWBUF, &__rawbuf, 0);
	FunInfoPut(fun, FUN_RAWBUF, &__rawsave, 0);
	__i = 0;
	__saved = 1;
      }
      /* restore raw buffer */
      else if( __saved ){
	FunInfoPut(fun, FUN_RAWBUF, &__rawbuf, 0);
	__i = 0;
	__saved = 0;
      }
      /* finished another row */
      NROW++;
      /* set up pointer to prev and next as needed */
      if( __rectype & REC_PREV ) prev = cur - 1;
      if( __rectype & REC_NEXT ) next = cur + 1;
      /* execute the expression */
      $EXPR
      /* write out this row with the new column */
      if( $ARGS > 1 ) WRITE_ROW;
    }
    /* update total */
    __total += __got;
  }

  /* any user-defined calls after we finish the row loop go here */
  $AFTER

  /* free row data */
  if( __rowbuf )  xfree(__rowbuf);
  if( __rawsave ) xfree(__rawsave);

  /* free arg strings */
  if( __xargs ){
    for(__i=0; __i<__nxarg; __i++){
      if( __xargs[__i] ) xfree(__xargs[__i]);
    }
    xfree(__xargs);
  }

  /* clean up -- close output before input to perform flush automatically */
  if( $ARGS > 1 )
    FunClose(ofun);
  FunClose(fun);

  /* delete program if necessary */
  if( __del ) unlink(argv[0]);
  return(0);

error:
  /* delete program if necessary */
  if( __del ) unlink(argv[0]);
  return(1);
}