Added quantiling UDAFs
[com/gs-lite.git] / include / lfta / schema_prototypes.h
1 #ifndef __SCHEMA_PROTOTYPES__\r
2 #define __SCHEMA_PROTOTYPES__\r
3 \r
4 /* ------------------------------------------------\r
5  Copyright 2014 AT&T Intellectual Property\r
6  Licensed under the Apache License, Version 2.0 (the "License");\r
7  you may not use this file except in compliance with the License.\r
8  You may obtain a copy of the License at\r
9  \r
10  http://www.apache.org/licenses/LICENSE-2.0\r
11  \r
12  Unless required by applicable law or agreed to in writing, software\r
13  distributed under the License is distributed on an "AS IS" BASIS,\r
14  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\r
15  See the License for the specific language governing permissions and\r
16  limitations under the License.\r
17  ------------------------------------------- */\r
18 \r
19 \r
20 #define PRECOMP\r
21 #include "gsconfig.h"\r
22 #include "gstypes.h"\r
23 \r
24 #include "fta.h"\r
25 #include "rts_external.h"\r
26 #include "packet.h"\r
27 #include "md_stdlib.h"\r
28 #include "schemaparser.h"\r
29 \r
30 \r
31 // *** SAMPLING RELATED CONSTANTS\r
32 // ******************************\r
33 \r
34 // Make sure the hash table sizes are powers of 2-1 since they are used to compute the module with an and.\r
35 // collions on the flow hash are handled properly so they are not that bad\r
36 #define MAX_FLOWRECORD_HASH 0x1fffff\r
37 // keep the collision rate low on denies\r
38 #define MAX_DENY_HASH 0x7fffff\r
39 // one out of SAMPLING_RATE+1 sampling\r
40 #define SAMPLING_RATE 19\r
41 // sampling probability\r
42 #define FLOWSAMPPROB (((gs_float_t)1)/((gs_float_t)SAMPLING_RATE+1))\r
43 // wait for SAMPLED_FLOW_TIMEOUT  seconds idle time to time a flow out\r
44 #define SAMPLED_FLOW_TIMEOUT 30\r
45 // check if we haven't seen that flow in SAMPLED_FLOW_IDLE_TIME seconds to make sure we don't catch it in the midle\r
46 #define SAMPLED_FLOW_IDLE_TIME 30\r
47 \r
48 // PACKET SAMPLING RATE one in SAMPLED_PACKETS will be sampled\r
49 #define SAMPLED_PACKETS 200\r
50 // SAMPLING probability\r
51 #define PACKETSAMPPROB (((gs_float_t)1)/((gs_float_t)SAMPLED_PACKETS))\r
52 \r
53 // COMBINE probability\r
54 #define COMBINEDPROB (((gs_float_t)1)-(((gs_float_t)1)-FLOWSAMPPROB)*(((gs_float_t)1)-PACKETSAMPPROB))\r
55 \r
56 /* General packet access functions */\r
57 \r
58 static inline gs_retval_t get_system_time(struct packet * p, gs_uint32_t * t)\r
59 {\r
60         *t=(gs_uint32_t) p->systemTime;\r
61         return 0;\r
62 }\r
63 static inline gs_retval_t get_schemaId(struct packet * p, gs_uint32_t * t)\r
64 {\r
65         *t=(gs_uint32_t) p->schema;\r
66         return 0;\r
67 }\r
68 \r
69 /* CSV access function using position as 3rd argument */\r
70 \r
71 static inline gs_retval_t get_csv_uint(struct packet * p, gs_uint32_t * t,gs_uint32_t pos)\r
72 {\r
73         if (p->ptype != PTYPE_CSV) return -1;\r
74         if (p->record.csv.numberfields < pos) return -1;\r
75     *t = strtoul((const char*)p->record.csv.fields[pos-1], NULL, 10);\r
76         return 0;\r
77 }\r
78 \r
79 static inline gs_retval_t get_csv_ullong(struct packet * p, gs_uint64_t * t,gs_uint32_t pos)\r
80 {\r
81     if (p->ptype != PTYPE_CSV) return -1;\r
82     if (p->record.csv.numberfields < pos) return -1;\r
83     *t = strtoull((const char*)p->record.csv.fields[pos-1], NULL, 10);    \r
84     return 0;\r
85 }\r
86 \r
87 static inline gs_retval_t get_csv_ip(struct packet * p, gs_uint32_t * t,gs_uint32_t pos)\r
88 {\r
89         unsigned ip1,ip2,ip3,ip4;\r
90     if (p->ptype != PTYPE_CSV) return -1;\r
91     if (p->record.csv.numberfields < pos) return -1;\r
92     sscanf((const char*) p->record.csv.fields[pos-1],"%u.%u.%u.%u",&ip1,&ip2,&ip3,&ip4);\r
93         *t=(ip1<<24)|(ip2<<16)|(ip3<<8)|ip4;\r
94     return 0;\r
95 }\r
96 static inline gs_retval_t get_csv_ipv6(struct packet * p, struct ipv6_str * t,gs_uint32_t pos)\r
97 {\r
98     gs_uint32_t v[8];\r
99         if (p->ptype != PTYPE_CSV) return -1;\r
100     if (p->record.csv.numberfields < pos) return -1;\r
101     sscanf((const char*) p->record.csv.fields[pos-1],"%x:%x:%x:%x:%x:%x:%x:%x",&v[0],&v[1],&v[2],&v[3],&v[4],&v[5],&v[6],&v[7]);\r
102         t->v[0]=htonl(v[0]<<16|v[1]);\r
103         t->v[1]=htonl(v[2]<<16|v[3]);\r
104         t->v[2]=htonl(v[4]<<16|v[5]);\r
105         t->v[3]=htonl(v[6]<<16|v[7]);\r
106         \r
107     return 0;\r
108 }\r
109 static inline gs_retval_t get_csv_string(struct packet * p, struct gs_string * t,gs_uint32_t pos)\r
110 {\r
111     \r
112     if (p->ptype != PTYPE_CSV) return -1;\r
113     if (p->record.csv.numberfields < pos) return -1;\r
114         t->data=(gs_sp_t)p->record.csv.fields[pos-1];\r
115     if (pos == p->record.csv.numberfields)\r
116         t->length=strlen((const char*)p->record.csv.fields[pos-1]);\r
117     else\r
118         t->length=p->record.csv.fields[pos] - p->record.csv.fields[pos-1] - 1;\r
119         t->owner=0;\r
120     return 0;\r
121 }\r
122 static inline gs_retval_t get_csv_bool(struct packet * p, gs_uint32_t * t,gs_uint32_t pos)\r
123 {\r
124     if (p->ptype != PTYPE_CSV) return -1;\r
125     if (p->record.csv.numberfields < pos) return -1;\r
126         *t=0;\r
127         if ((strlen((const char*)p->record.csv.fields[pos-1])==4) &&\r
128                 (strncasecmp("TRUE",(const char*)p->record.csv.fields[pos-1],4) ==0) ) {\r
129                 *t=1;\r
130         }\r
131     return 0;\r
132 }\r
133 static inline gs_retval_t get_csv_int(struct packet * p, gs_int32_t * t,gs_uint32_t pos)\r
134 {\r
135     if (p->ptype != PTYPE_CSV) return -1;\r
136     if (p->record.csv.numberfields < pos) return -1;\r
137     *t = strtol((const char*)p->record.csv.fields[pos-1], NULL, 10);\r
138     return 0;\r
139 }\r
140 static inline gs_retval_t get_csv_llong(struct packet * p, gs_int64_t * t,gs_uint32_t pos)\r
141 {\r
142     if (p->ptype != PTYPE_CSV) return -1;\r
143     if (p->record.csv.numberfields < pos) return -1;\r
144     *t = strtoll((const char*)p->record.csv.fields[pos-1], NULL, 10);\r
145     return 0;\r
146 }\r
147 static inline gs_retval_t get_csv_float(struct packet * p, gs_float_t * t,gs_uint32_t pos)\r
148 {\r
149     if (p->ptype != PTYPE_CSV) return -1;\r
150     if (p->record.csv.numberfields < pos) return -1;\r
151     *t = strtod((const char*)p->record.csv.fields[pos-1], NULL);\r
152     return 0;\r
153 }\r
154 \r
155 #include <lfta/csv_macro.h>\r
156 \r
157 static inline __attribute__((always_inline)) unsigned int gs_strtoul (const char *str, size_t len) {\r
158         unsigned int value = 0;\r
159 \r
160         switch (len) { // handle up to 10 digits, assume we're 32-bit\r
161             case 10:    value += (str[len-10] - '0') * 1000000000;\r
162             case  9:    value += (str[len- 9] - '0') * 100000000;\r
163             case  8:    value += (str[len- 8] - '0') * 10000000;\r
164             case  7:    value += (str[len- 7] - '0') * 1000000;\r
165             case  6:    value += (str[len- 6] - '0') * 100000;\r
166             case  5:    value += (str[len- 5] - '0') * 10000;\r
167             case  4:    value += (str[len- 4] - '0') * 1000;\r
168             case  3:    value += (str[len- 3] - '0') * 100;\r
169             case  2:    value += (str[len- 2] - '0') * 10;\r
170             case  1:    value += (str[len- 1] - '0');\r
171                 return value;\r
172             default:\r
173                 return 0;\r
174         }\r
175 }\r
176 \r
177 static inline __attribute__((always_inline)) unsigned long long gs_strtoull (const char *str, size_t len) {\r
178         unsigned long long value = 0;\r
179 \r
180         switch (len) { // handle up to 10 digits, assume we're 32-bit\r
181             case 20:    value += (str[len-20] - '0') * 10000000000000000000UL;\r
182             case 19:    value += (str[len-19] - '0') * 1000000000000000000UL;\r
183             case 18:    value += (str[len-18] - '0') * 100000000000000000UL;\r
184             case 17:    value += (str[len-17] - '0') * 10000000000000000UL;\r
185             case 16:    value += (str[len-16] - '0') * 1000000000000000UL;\r
186             case 15:    value += (str[len-15] - '0') * 100000000000000UL;\r
187             case 14:    value += (str[len-14] - '0') * 10000000000000UL;\r
188             case 13:    value += (str[len-13] - '0') * 1000000000000UL;\r
189             case 12:    value += (str[len-12] - '0') * 100000000000UL;\r
190             case 11:    value += (str[len-11] - '0') * 10000000000UL;\r
191             case 10:    value += (str[len-10] - '0') * 1000000000UL;\r
192             case  9:    value += (str[len- 9] - '0') * 100000000UL;\r
193             case  8:    value += (str[len- 8] - '0') * 10000000UL;\r
194             case  7:    value += (str[len- 7] - '0') * 1000000UL;\r
195             case  6:    value += (str[len- 6] - '0') * 100000UL;\r
196             case  5:    value += (str[len- 5] - '0') * 10000UL;\r
197             case  4:    value += (str[len- 4] - '0') * 1000UL;\r
198             case  3:    value += (str[len- 3] - '0') * 100UL;\r
199             case  2:    value += (str[len- 2] - '0') * 10UL;\r
200             case  1:    value += (str[len- 1] - '0');\r
201                 return value;\r
202             default:\r
203                 return 0;\r
204         }\r
205 }\r
206 \r
207 static inline gs_retval_t get_csv2_uint(struct packet * p, gs_uint32_t * t,gs_uint32_t pos)\r
208 {\r
209 //    *t = strtoul((const char*)p->record.csv2.fields[pos-1], NULL, 10);\r
210     *t = gs_strtoul((const char*)p->record.csv2.fields[pos-1], p->record.csv2.field_lens[pos-1]);\r
211     \r
212         return 0;\r
213 }\r
214 \r
215 static inline gs_retval_t get_csv2_ullong(struct packet * p, gs_uint64_t * t,gs_uint32_t pos)\r
216 {\r
217 //    *t = strtoull((const char*)p->record.csv2.fields[pos-1], NULL, 10);    \r
218     *t = gs_strtoull((const char*)p->record.csv2.fields[pos-1], p->record.csv2.field_lens[pos-1]);\r
219     return 0;\r
220 }\r
221 \r
222 static inline gs_retval_t get_csv2_ip(struct packet * p, gs_uint32_t * t,gs_uint32_t pos)\r
223 {\r
224         unsigned ip1,ip2,ip3,ip4;\r
225     sscanf((const char*) p->record.csv2.fields[pos-1],"%u.%u.%u.%u",&ip1,&ip2,&ip3,&ip4);\r
226         *t=(ip1<<24)|(ip2<<16)|(ip3<<8)|ip4;\r
227     return 0;\r
228 }\r
229 static inline gs_retval_t get_csv2_ipv6(struct packet * p, struct ipv6_str * t,gs_uint32_t pos)\r
230 {\r
231     gs_uint32_t v[8];\r
232     sscanf((const char*) p->record.csv2.fields[pos-1],"%x:%x:%x:%x:%x:%x:%x:%x",&v[0],&v[1],&v[2],&v[3],&v[4],&v[5],&v[6],&v[7]);\r
233         t->v[0]=htonl(v[0]<<16|v[1]);\r
234         t->v[1]=htonl(v[2]<<16|v[3]);\r
235         t->v[2]=htonl(v[4]<<16|v[5]);\r
236         t->v[3]=htonl(v[6]<<16|v[7]);\r
237         \r
238     return 0;\r
239 }\r
240 static inline gs_retval_t get_csv2_string(struct packet * p, struct gs_string * t,gs_uint32_t pos)\r
241\r
242         t->data=(gs_sp_t)p->record.csv2.fields[pos-1];\r
243     /*\r
244     if (pos == p->record.csv2.numberfields)\r
245         t->length=strlen((const char*)p->record.csv2.fields[pos-1]);\r
246     else\r
247         t->length=p->record.csv2.fields[pos] - p->record.csv2.fields[pos-1] - 1;\r
248     */\r
249     t->length=p->record.csv2.field_lens[pos-1];\r
250         t->owner=0;\r
251     return 0;\r
252 }\r
253 static inline gs_retval_t get_csv2_bool(struct packet * p, gs_uint32_t * t,gs_uint32_t pos)\r
254 {\r
255         *t=0;\r
256         if ((strlen((const char*)p->record.csv2.fields[pos-1])==4) &&\r
257                 (strncasecmp("TRUE",(const char*)p->record.csv2.fields[pos-1],4) ==0) ) {\r
258                 *t=1;\r
259         }\r
260     return 0;\r
261 }\r
262 static inline gs_retval_t get_csv2_int(struct packet * p, gs_int32_t * t,gs_uint32_t pos)\r
263 {\r
264     *t = strtol((const char*)p->record.csv2.fields[pos-1], NULL, 10);\r
265     return 0;\r
266 }\r
267 static inline gs_retval_t get_csv2_llong(struct packet * p, gs_int64_t * t,gs_uint32_t pos)\r
268 {\r
269     *t = strtoll((const char*)p->record.csv2.fields[pos-1], NULL, 10);\r
270     return 0;\r
271 }\r
272 static inline gs_retval_t get_csv2_float(struct packet * p, gs_float_t * t,gs_uint32_t pos)\r
273 {\r
274     *t = strtod((const char*)p->record.csv2.fields[pos-1], NULL);\r
275     return 0;\r
276 }\r
277 \r
278 #include <lfta/csv2_macro.h>\r
279 \r
280 /* GDAT access function using position as 3rd argument */\r
281 \r
282 //#define GDATDEBUG\r
283 \r
284 static inline gs_retval_t get_gdat_uint(struct packet * p, gs_uint32_t * t,gs_uint32_t pos)\r
285 {\r
286     struct access_result ar;\r
287 #ifdef GDATDEBUG\r
288         fprintf(stderr,"Decode uint");\r
289 #endif\r
290         if (p->ptype != PTYPE_GDAT) return -1;\r
291 #ifdef GDATDEBUG\r
292     fprintf(stderr,".");\r
293 #endif\r
294         if (p->record.gdat.numfields<pos) return -1;\r
295 #ifdef GDATDEBUG\r
296     fprintf(stderr,".");\r
297 #endif\r
298         ar=ftaschema_get_field_by_index(p->record.gdat.schema,pos-1,p->record.gdat.data,p->record.gdat.datasz);\r
299 #ifdef GDATDEBUG\r
300     fprintf(stderr,".");\r
301 #endif\r
302         if (ar.field_data_type!=UINT_TYPE) return -1;\r
303 #ifdef GDATDEBUG\r
304     fprintf(stderr,"DONE\n");\r
305 #endif\r
306         *t=ar.r.ui;\r
307     return 0;\r
308 }\r
309 \r
310 static inline gs_retval_t get_gdat_ullong(struct packet * p, gs_uint64_t * t,gs_uint32_t pos)\r
311 {\r
312     struct access_result ar;\r
313 #ifdef GDATDEBUG\r
314     fprintf(stderr,"Decode ullong");\r
315 #endif\r
316     if (p->ptype != PTYPE_GDAT) return -1;\r
317 #ifdef GDATDEBUG\r
318     fprintf(stderr,".");\r
319 #endif\r
320     if (p->record.gdat.numfields<pos) return -1;\r
321 #ifdef GDATDEBUG\r
322     fprintf(stderr,".");\r
323 #endif\r
324     ar=ftaschema_get_field_by_index(p->record.gdat.schema,pos-1,p->record.gdat.data,p->record.gdat.datasz);\r
325 #ifdef GDATDEBUG\r
326     fprintf(stderr,".");\r
327 #endif\r
328     if (ar.field_data_type!=ULLONG_TYPE) return -1;\r
329 #ifdef GDATDEBUG\r
330     fprintf(stderr,"DONE\n");\r
331 #endif\r
332     *t=ar.r.ul;\r
333     return 0;\r
334 }\r
335 \r
336 static inline gs_retval_t get_gdat_ip(struct packet * p, gs_uint32_t * t,gs_uint32_t pos)\r
337 {\r
338     struct access_result ar;\r
339     if (p->ptype != PTYPE_GDAT) return -1;\r
340 #ifdef GDATDEBUG\r
341     fprintf(stderr,"Decode ip");\r
342 #endif\r
343     if (p->record.gdat.numfields<pos) return -1;\r
344 #ifdef GDATDEBUG\r
345     fprintf(stderr,".");\r
346 #endif\r
347     ar=ftaschema_get_field_by_index(p->record.gdat.schema,pos-1,p->record.gdat.data,p->record.gdat.datasz);\r
348 #ifdef GDATDEBUG\r
349     fprintf(stderr,".");\r
350 #endif\r
351     if (ar.field_data_type!=IP_TYPE) return -1;\r
352 #ifdef GDATDEBUG\r
353     fprintf(stderr,"DONE\n");\r
354 #endif\r
355     *t=ar.r.ui;\r
356     return 0;\r
357 }\r
358 static inline gs_retval_t get_gdat_ipv6(struct packet * p, struct ipv6_str * t,gs_uint32_t pos)\r
359 {\r
360     struct access_result ar;\r
361     if (p->ptype != PTYPE_GDAT) return -1;\r
362 #ifdef GDATDEBUG\r
363     fprintf(stderr,"Decode ipv6");\r
364 #endif\r
365     if (p->record.gdat.numfields<pos) return -1;\r
366 #ifdef GDATDEBUG\r
367     fprintf(stderr,".");\r
368 #endif\r
369     ar=ftaschema_get_field_by_index(p->record.gdat.schema,pos-1,p->record.gdat.data,p->record.gdat.datasz);\r
370 #ifdef GDATDEBUG\r
371     fprintf(stderr,".");\r
372 #endif\r
373     if (ar.field_data_type!=IPV6_TYPE) return -1;\r
374 #ifdef GDATDEBUG\r
375     fprintf(stderr,"DONE\n");\r
376 #endif\r
377     t->v[0]=ar.r.ip6.v[0];\r
378     t->v[1]=ar.r.ip6.v[1];\r
379     t->v[2]=ar.r.ip6.v[2];\r
380     t->v[3]=ar.r.ip6.v[3];\r
381     return 0;\r
382 }\r
383 static inline gs_retval_t get_gdat_string(struct packet * p, struct gs_string * t,gs_uint32_t pos)\r
384 {\r
385     struct access_result ar;\r
386 #ifdef GDATDEBUG\r
387     fprintf(stderr,"Decode string");\r
388 #endif\r
389     if (p->ptype != PTYPE_GDAT) return -1;\r
390 #ifdef GDATDEBUG\r
391     fprintf(stderr,".");\r
392 #endif\r
393     if (p->record.gdat.numfields<pos) return -1;\r
394 #ifdef GDATDEBUG\r
395     fprintf(stderr,".");\r
396 #endif\r
397     ar=ftaschema_get_field_by_index(p->record.gdat.schema,pos-1,p->record.gdat.data,p->record.gdat.datasz);\r
398 #ifdef GDATDEBUG\r
399     fprintf(stderr,".");\r
400 #endif\r
401     if (ar.field_data_type!=VSTR_TYPE) return -1;\r
402 #ifdef GDATDEBUG\r
403     fprintf(stderr,"DONE\n");\r
404 #endif\r
405     t->data=(gs_sp_t)ar.r.vs.offset;\r
406         t->length=ar.r.vs.length;\r
407     return 0;\r
408 }\r
409 static inline gs_retval_t get_gdat_bool(struct packet * p, gs_uint32_t * t,gs_uint32_t pos)\r
410 {\r
411     struct access_result ar;\r
412 #ifdef GDATDEBUG\r
413     fprintf(stderr,"Decode bool");\r
414 #endif\r
415     if (p->ptype != PTYPE_GDAT) return -1;\r
416 #ifdef GDATDEBUG\r
417     fprintf(stderr,".");\r
418 #endif\r
419     if (p->record.gdat.numfields<pos) return -1;\r
420 #ifdef GDATDEBUG\r
421     fprintf(stderr,".");\r
422 #endif\r
423     ar=ftaschema_get_field_by_index(p->record.gdat.schema,pos-1,p->record.gdat.data,p->record.gdat.datasz);\r
424 #ifdef GDATDEBUG\r
425     fprintf(stderr,".");\r
426 #endif\r
427     if (ar.field_data_type!=BOOL_TYPE) return -1;\r
428 #ifdef GDATDEBUG\r
429     fprintf(stderr,"DONE\n");\r
430 #endif\r
431     *t=ar.r.ui;\r
432     return 0;\r
433 }\r
434 static inline gs_retval_t get_gdat_int(struct packet * p, gs_int32_t * t,gs_uint32_t pos)\r
435 {\r
436     struct access_result ar;\r
437 #ifdef GDATDEBUG\r
438     fprintf(stderr,"Decode int");\r
439 #endif\r
440     if (p->ptype != PTYPE_GDAT) return -1;\r
441 #ifdef GDATDEBUG\r
442     fprintf(stderr,".");\r
443 #endif\r
444     if (p->record.gdat.numfields<pos) return -1;\r
445 #ifdef GDATDEBUG\r
446     fprintf(stderr,".");\r
447 #endif\r
448     ar=ftaschema_get_field_by_index(p->record.gdat.schema,pos-1,p->record.gdat.data,p->record.gdat.datasz);\r
449 #ifdef GDATDEBUG\r
450     fprintf(stderr,".");\r
451 #endif\r
452     if (ar.field_data_type!=INT_TYPE) return -1;\r
453 #ifdef GDATDEBUG\r
454     fprintf(stderr,"DONE\n");\r
455 #endif\r
456     *t=ar.r.i;\r
457     return 0;\r
458 }\r
459 static inline gs_retval_t get_gdat_llong(struct packet * p, gs_int64_t * t,gs_uint32_t pos)\r
460 {\r
461     struct access_result ar;\r
462 #ifdef GDATDEBUG\r
463     fprintf(stderr,"Decode llong");\r
464 #endif\r
465     if (p->ptype != PTYPE_GDAT) return -1;\r
466 #ifdef GDATDEBUG\r
467     fprintf(stderr,".");\r
468 #endif\r
469     if (p->record.gdat.numfields<pos) return -1;\r
470 #ifdef GDATDEBUG\r
471     fprintf(stderr,".");\r
472 #endif\r
473     ar=ftaschema_get_field_by_index(p->record.gdat.schema,pos-1,p->record.gdat.data,p->record.gdat.datasz);\r
474 #ifdef GDATDEBUG\r
475     fprintf(stderr,".");\r
476 #endif\r
477     if (ar.field_data_type!=LLONG_TYPE) return -1;\r
478 #ifdef GDATDEBUG\r
479     fprintf(stderr,"DONE\n");\r
480 #endif\r
481     *t=ar.r.l;\r
482     return 0;\r
483 }\r
484 static inline gs_retval_t get_gdat_float(struct packet * p, gs_float_t * t,gs_uint32_t pos)\r
485 {\r
486     struct access_result ar;\r
487 #ifdef GDATDEBUG\r
488     fprintf(stderr,"Decode float");\r
489 #endif\r
490     if (p->ptype != PTYPE_GDAT) return -1;\r
491 #ifdef GDATDEBUG\r
492     fprintf(stderr,".");\r
493 #endif\r
494     if (p->record.gdat.numfields<pos) return -1;\r
495 #ifdef GDATDEBUG\r
496     fprintf(stderr,".");\r
497 #endif\r
498     ar=ftaschema_get_field_by_index(p->record.gdat.schema,pos-1,p->record.gdat.data,p->record.gdat.datasz);\r
499 #ifdef GDATDEBUG\r
500     fprintf(stderr,".");\r
501 #endif\r
502     if (ar.field_data_type!=FLOAT_TYPE) return -1;\r
503 #ifdef GDATDEBUG\r
504     fprintf(stderr,"DONE\n");\r
505 #endif\r
506     *t=ar.r.f;\r
507     return 0;\r
508 }\r
509 \r
510 #include <lfta/gdat_macro.h>\r
511 \r
512 // External functions\r
513 \r
514 \r
515 \r
516 \r
517 #endif\r
518 \r