1 #line 982 "../../src/builtin/snarf.m4"
2 /* -*- buffer-read-only: t -*- vi: set ro:
3    THIS FILE IS GENERATED AUTOMATICALLY.  PLEASE DO NOT EDIT.
4 */
5 #line 982
6 #ifdef HAVE_CONFIG_H
7 #line 982
8 # include <config.h>
9 #line 982
10 #endif
11 #line 982
12 #include <sys/types.h>
13 #line 982
14 
15 #line 982
16 #include "mailfromd.h"
17 #line 982
18 #include "prog.h"
19 #line 982
20 #include "builtin.h"
21 #line 982
22 
23 #line 982
24 
25 #line 1022 "../../src/builtin/snarf.m4"
26 
27 /* End of snarf.m4 */
28 #line 1 "geoip2.bi"
29 /* This file is part of Mailfromd.             -*- c -*-
30    Copyright (C) 2020-2021 Sergey Poznyakoff
31 
32    This program is free software; you can redistribute it and/or modify
33    it under the terms of the GNU General Public License as published by
34    the Free Software Foundation; either version 3, or (at your option)
35    any later version.
36 
37    This program is distributed in the hope that it will be useful,
38    but WITHOUT ANY WARRANTY; without even the implied warranty of
39    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
40    GNU General Public License for more details.
41 
42    You should have received a copy of the GNU General Public License
43    along with this program.  If not, see <http://www.gnu.org/licenses/>. */
44 
45 
46 #ifdef WITH_GEOIP2
47 #line 18
48 
49 #include <inttypes.h>
50 #include <maxminddb.h>
51 
52 #define DEFAULT_DIR  "/usr/share/GeoIP"
53 #define DEFAULT_FILE "GeoLite2-City.mmdb"
54 #define GEOIP2_DEFAULT_DATABASE DEFAULT_DIR "/" DEFAULT_FILE
55 
56 struct geoip2_storage {
57 	char *dbname;
58 	MMDB_s db;
59 	int is_open;
60 };
61 
62 static void *
geoip2_alloc(void)63 geoip2_alloc(void)
64 {
65 	struct geoip2_storage *gs = mu_zalloc(sizeof(*gs));
66 	gs->is_open = 0;
67 	return gs;
68 }
69 
70 static void
geoip2_close(struct geoip2_storage * gs)71 geoip2_close(struct geoip2_storage *gs)
72 {
73 	if (gs->is_open) {
74 		MMDB_close(&gs->db);
75 		gs->is_open = 0;
76 	}
77 }
78 
79 static void
geoip2_destroy(void * data)80 geoip2_destroy(void *data)
81 {
82 	struct geoip2_storage *gs = data;
83 	geoip2_close(gs);
84 	free(gs->dbname);
85 	free(gs);
86 }
87 
88 
89 #line 58
90 
91 #line 58
92 static int GEOIP2_id;
93 #line 58 "geoip2.bi"
94 
95 
96 static struct geoip2_storage *
geoip2_open(eval_environ_t env)97 geoip2_open(eval_environ_t env)
98 {
99 	int rc;
100 	struct geoip2_storage *gs = env_get_builtin_priv(env,GEOIP2_id);
101 	if (!gs->is_open) {
102 		if (!gs->dbname)
103 			gs->dbname = mu_strdup(GEOIP2_DEFAULT_DATABASE);
104 		rc = MMDB_open(gs->dbname, MMDB_MODE_MMAP, &gs->db);
105 			if (!(rc == MMDB_SUCCESS))
106 #line 69
107 		(
108 #line 69
109 	env_throw_bi(env, mfe_failure, NULL, "can't open database \"%s\": %s",gs->dbname,MMDB_strerror(rc))
110 #line 69
111 )
112 #line 72
113 ;
114 		gs->is_open = 1;
115 	}
116 	return gs;
117 }
118 
119 void
120 #line 78
bi_geoip2_dbname(eval_environ_t env)121 bi_geoip2_dbname(eval_environ_t env)
122 #line 78
123 
124 #line 78
125 
126 #line 78 "geoip2.bi"
127 {
128 #line 78
129 
130 #line 78
131 
132 #line 78
133 
134 #line 78
135 
136 #line 78
137 
138 #line 78
139 
140 #line 78
141         adjust_stack(env, 0);
142 #line 78
143 
144 #line 78
145 
146 #line 78
147 	if (builtin_module_trace(BUILTIN_IDX_geoip2))
148 #line 78
149 		prog_trace(env, "geoip2_dbname");;
150 #line 78
151 
152 {
153 	struct geoip2_storage *gs = env_get_builtin_priv(env,GEOIP2_id);
154 
155 #line 81
156 do {
157 #line 81
158   pushs(env, gs->dbname ? gs->dbname : GEOIP2_DEFAULT_DATABASE);
159 #line 81
160   goto endlab;
161 #line 81
162 } while (0);
163 }
164 endlab:
165 #line 83
166         env_function_cleanup_flush(env, NULL);
167 #line 83
168 	return;
169 #line 83
170 }
171 
172 void
173 #line 85
bi_geoip2_open(eval_environ_t env)174 bi_geoip2_open(eval_environ_t env)
175 #line 85
176 
177 #line 85
178 
179 #line 85 "geoip2.bi"
180 {
181 #line 85
182 
183 #line 85
184 
185 #line 85
186 
187 #line 85
188 char *  name;
189 #line 85
190 
191 #line 85
192 get_string_arg(env, 0, &name);
193 #line 85
194 
195 #line 85
196 
197 #line 85
198         adjust_stack(env, 1);
199 #line 85
200 
201 #line 85
202 
203 #line 85
204 	if (builtin_module_trace(BUILTIN_IDX_geoip2))
205 #line 85
206 		prog_trace(env, "geoip2_open %s",name);;
207 #line 85
208 
209 {
210 	struct geoip2_storage *gs = env_get_builtin_priv(env,GEOIP2_id);
211 	geoip2_close(gs);
212 	free(gs->dbname);
213 	gs->dbname = mu_strdup(name);
214 	geoip2_open(env);
215 }
216 
217 #line 93
218         env_function_cleanup_flush(env, NULL);
219 #line 93
220 	return;
221 #line 93
222 }
223 
224 static void
conv_utf_string(eval_environ_t env,MMDB_entry_data_s * dptr)225 conv_utf_string(eval_environ_t env, MMDB_entry_data_s *dptr)
226 {
227 	heap_obstack_grow(env, (void*)dptr->utf8_string, dptr->data_size);
228 }
229 
230 static void
conv_uint16(eval_environ_t env,MMDB_entry_data_s * dptr)231 conv_uint16(eval_environ_t env, MMDB_entry_data_s *dptr)
232 {
233 	heap_obstack_sprintf(env, "%" PRIu16, dptr->uint16);
234 }
235 
236 static void
conv_uint32(eval_environ_t env,MMDB_entry_data_s * dptr)237 conv_uint32(eval_environ_t env, MMDB_entry_data_s *dptr)
238 {
239 	heap_obstack_sprintf(env, "%" PRIu32, dptr->uint32);
240 }
241 
242 static void
conv_int32(eval_environ_t env,MMDB_entry_data_s * dptr)243 conv_int32(eval_environ_t env, MMDB_entry_data_s *dptr)
244 {
245 	heap_obstack_sprintf(env, "%" PRIi32, dptr->int32);
246 }
247 
248 static void
conv_bool(eval_environ_t env,MMDB_entry_data_s * dptr)249 conv_bool(eval_environ_t env, MMDB_entry_data_s *dptr)
250 {
251 	heap_obstack_sprintf(env, "%01d", dptr->boolean ? 1 : 0);
252 }
253 
254 static void
conv_double(eval_environ_t env,MMDB_entry_data_s * dptr)255 conv_double(eval_environ_t env, MMDB_entry_data_s *dptr)
256 {
257 	heap_obstack_sprintf(env, "%g", dptr->double_value);
258 }
259 
260 static void
conv_float(eval_environ_t env,MMDB_entry_data_s * dptr)261 conv_float(eval_environ_t env, MMDB_entry_data_s *dptr)
262 {
263 	heap_obstack_sprintf(env, "%g", dptr->float_value);
264 }
265 
266 static void (*entry_conv[]) (eval_environ_t, MMDB_entry_data_s *) = {
267         [MMDB_DATA_TYPE_UTF8_STRING] = conv_utf_string,
268         [MMDB_DATA_TYPE_UINT16]      = conv_uint16,
269         [MMDB_DATA_TYPE_UINT32]      = conv_uint32,
270         [MMDB_DATA_TYPE_INT32]       = conv_int32,
271         [MMDB_DATA_TYPE_BOOLEAN]     = conv_bool,
272         [MMDB_DATA_TYPE_DOUBLE]      = conv_double,
273         [MMDB_DATA_TYPE_FLOAT]       = conv_float
274 };
275 
276 void
277 #line 147
bi_geoip2_get(eval_environ_t env)278 bi_geoip2_get(eval_environ_t env)
279 #line 147
280 
281 #line 147
282 
283 #line 147 "geoip2.bi"
284 {
285 #line 147
286 
287 #line 147
288 
289 #line 147
290 
291 #line 147
292 char * MFL_DATASEG ip;
293 #line 147
294         char * MFL_DATASEG pathstr;
295 #line 147
296 
297 #line 147
298 get_string_arg(env, 0, &ip);
299 #line 147
300         get_string_arg(env, 1, &pathstr);
301 #line 147
302 
303 #line 147
304 
305 #line 147
306         adjust_stack(env, 2);
307 #line 147
308 
309 #line 147
310 
311 #line 147
312 	if (builtin_module_trace(BUILTIN_IDX_geoip2))
313 #line 147
314 		prog_trace(env, "geoip2_get %s %s",ip, pathstr);;
315 #line 147
316 
317 {
318 	struct geoip2_storage *gs = geoip2_open(env);
319 	MMDB_lookup_result_s result;
320         int mmdb_error;
321 	int gai_error;
322 	MMDB_entry_data_s entry_data;
323 	int rc;
324 	struct mu_wordsplit ws;
325 
326 	result = MMDB_lookup_string(&gs->db, ip, &gai_error, &mmdb_error);
327 		if (!(gai_error == 0))
328 #line 158
329 		(
330 #line 158
331 	env_throw_bi(env, mfe_failure, "geoip2_get", "%s: %s",ip,gai_strerror(gai_error))
332 #line 158
333 )
334 #line 161
335 ;
336 
337 		if (!(mmdb_error == MMDB_SUCCESS))
338 #line 163
339 		(
340 #line 163
341 	env_throw_bi(env, mfe_failure, "geoip2_get", "%s: %s: %s",pathstr,ip,MMDB_strerror(mmdb_error))
342 #line 163
343 )
344 #line 166
345 ;
346 
347 		if (!(result.found_entry != 0))
348 #line 168
349 		(
350 #line 168
351 	env_throw_bi(env, mfe_not_found, "geoip2_get", _("IP not found in the database"))
352 #line 168
353 )
354 #line 170
355 ;
356 
357 	ws.ws_delim = ".";
358 	rc = mu_wordsplit(pathstr, &ws, WRDSF_DELIM);
359 	if (rc != 0) {
360 		char const *errstr = mu_wordsplit_strerror(&ws);
361 		mu_wordsplit_free(&ws);
362 		(
363 #line 177
364 	env_throw_bi(env, mfe_failure, "geoip2_get", "can't split string %s: %s",pathstr,errstr)
365 #line 177
366 );
367 #line 180
368 	}
369 
370 	rc = MMDB_aget_value(&result.entry, &entry_data,
371 			     (const char * const* const) ws.ws_wordv);
372 	mu_wordsplit_free(&ws);
373 
374 		if (!(rc == MMDB_SUCCESS))
375 #line 186
376 		(
377 #line 186
378 	env_throw_bi(env, (rc == MMDB_LOOKUP_PATH_DOES_NOT_MATCH_DATA_ERROR ||
379 #line 186
380 		   rc == MMDB_INVALID_LOOKUP_PATH_ERROR)
381 #line 186
382 		     ? mfe_range : mfe_failure, "geoip2_get", "%s %s: MMDB_aget_value %s",pathstr,ip,MMDB_strerror(rc))
383 #line 186
384 )
385 #line 191
386 ;
387 
388 	if (!entry_data.has_data)
389 
390 #line 194
391 do {
392 #line 194
393   pushs(env, "");
394 #line 194
395   goto endlab;
396 #line 194
397 } while (0);
398 
399 		if (!(entry_data.type >= 0
400 #line 196
401 		  && entry_data.type <= sizeof (entry_conv) / sizeof (entry_conv[0])
402 #line 196
403 		  && entry_conv[entry_data.type]))
404 #line 196
405 		(
406 #line 196
407 	env_throw_bi(env, mfe_failure, "geoip2_get", "%s: can't format %s of type %d",ip,pathstr,entry_data.type)
408 #line 196
409 )
410 #line 201
411 ;
412 
413 	heap_obstack_begin(env);
414 	heap_obstack_sprintf(env, "%s","string result:");
415 	entry_conv[entry_data.type] (env, &entry_data);
416 	do { char __c = 0; heap_obstack_grow(env, &__c, 1); } while(0);
417 
418 #line 207
419 do {
420 #line 207
421   push(env, (STKVAL) (heap_obstack_finish(env)));
422 #line 207
423   goto endlab;
424 #line 207
425 } while (0);
426 }
427 endlab:
428 #line 209
429         env_function_cleanup_flush(env, NULL);
430 #line 209
431 	return;
432 #line 209
433 }
434 
435 struct object_type {
436 	enum { OBJ_MAP, OBJ_ARRAY } type;
437 	size_t count;
438 	unsigned level;
439 	struct object_type *prev;
440 };
441 
442 static inline void
object_type_push(struct object_type ** otp,int type,size_t count)443 object_type_push(struct object_type **otp, int type, size_t count)
444 {
445 	struct object_type *t = mu_alloc(sizeof(*t));
446 	t->type = type;
447 	t->count = count;
448 	t->prev = *otp;
449 	t->level = t->prev ? t->prev->level + 1 : 1;
450 	*otp = t;
451 }
452 
453 static inline void
object_type_pop(struct object_type ** otp)454 object_type_pop(struct object_type **otp)
455 {
456 	struct object_type *t = *otp;
457 	*otp = t->prev;
458 	free(t);
459 }
460 
461 void
462 #line 237
bi_geoip2_get_json(eval_environ_t env)463 bi_geoip2_get_json(eval_environ_t env)
464 #line 237
465 
466 #line 237
467 
468 #line 237 "geoip2.bi"
469 {
470 #line 237
471 
472 #line 237
473 
474 #line 237
475 long __bi_argcnt;
476 #line 237
477 char * MFL_DATASEG ip;
478 #line 237
479         long  indent;
480 #line 237
481 
482 #line 237
483 get_string_arg(env, 1, &ip);
484 #line 237
485         get_numeric_arg(env, 2, &indent);
486 #line 237
487 
488 #line 237
489 get_numeric_arg(env, 0, &__bi_argcnt);
490 #line 237
491         adjust_stack(env, __bi_argcnt + 1);
492 #line 237
493 
494 #line 237
495 
496 #line 237
497 	if (builtin_module_trace(BUILTIN_IDX_geoip2))
498 #line 237
499 		prog_trace(env, "geoip2_get_json %s %lu",ip, ((__bi_argcnt > 1) ? indent : 0));;
500 #line 237
501 
502 {
503 	struct geoip2_storage *gs = geoip2_open(env);
504 	MMDB_lookup_result_s result;
505         int mmdb_error;
506 	int gai_error;
507 	int rc;
508 	MMDB_entry_data_list_s *data_list, *p;
509 	struct object_type *type = NULL;
510 	int iskey = 1;
511 	size_t i;
512 	char *indent_str = NULL;
513 
514 	result = MMDB_lookup_string(&gs->db, ip, &gai_error, &mmdb_error);
515 		if (!(gai_error == 0))
516 #line 251
517 		(
518 #line 251
519 	env_throw_bi(env, mfe_failure, "geoip2_get_json", "%s: %s",ip,gai_strerror(gai_error))
520 #line 251
521 )
522 #line 254
523 ;
524 
525 		if (!(mmdb_error == MMDB_SUCCESS))
526 #line 256
527 		(
528 #line 256
529 	env_throw_bi(env, mfe_failure, "geoip2_get_json", "%s: %s",ip,MMDB_strerror(mmdb_error))
530 #line 256
531 )
532 #line 259
533 ;
534 
535 		if (!(result.found_entry != 0))
536 #line 261
537 		(
538 #line 261
539 	env_throw_bi(env, mfe_not_found, "geoip2_get_json", _("IP not found in the database"))
540 #line 261
541 )
542 #line 263
543 ;
544 
545 	rc = MMDB_get_entry_data_list(&result.entry, &data_list);
546 		if (!(rc == MMDB_SUCCESS))
547 #line 266
548 		(
549 #line 266
550 	env_throw_bi(env, mfe_failure, "geoip2_get_json", "%s: MMDB_aget_value %s",ip,MMDB_strerror(rc))
551 #line 266
552 )
553 #line 269
554 ;
555 
556 	/*MMDB_dump_entry_data_list(stdout, data_list, 4);*/
557 
558 	indent = ((__bi_argcnt > 1) ? indent : 0);
559 	if (indent) {
560 		indent_str = mu_alloc(indent+1);
561 		memset(indent_str, ' ', indent);
562 		indent_str[indent] = 0;
563 	}
564 
565 	heap_obstack_begin(env);
566 	for (p = data_list; p; p = p->next) {
567 		if (iskey && type && indent_str) {
568 			do { char __c = '\n'; heap_obstack_grow(env, &__c, 1); } while(0);
569 			for (i = 0; i < type->level; i++)
570 
571 #line 285
572 do {
573 #line 285
574   char *__s = indent_str;
575 #line 285
576   heap_obstack_grow(env, __s, strlen(__s));
577 #line 285
578 } while (0);
579 		}
580 
581 		if (type == NULL && p->entry_data.type != MMDB_DATA_TYPE_MAP) {
582 			heap_obstack_cancel(env);
583 			free(indent_str);
584 			MMDB_free_entry_data_list(data_list);
585 			(
586 #line 292
587 	env_throw_bi(env, mfe_failure, "geoip2_get_json", "%s",_("malformed data list"))
588 #line 292
589 );
590 #line 295
591 		}
592 
593 		switch (p->entry_data.type) {
594 		case MMDB_DATA_TYPE_MAP:
595 			object_type_push(&type, OBJ_MAP, p->entry_data.data_size);
596 			do { char __c = '{'; heap_obstack_grow(env, &__c, 1); } while(0);
597 			iskey = 1;
598 			continue;
599 
600 		case MMDB_DATA_TYPE_ARRAY:
601 			object_type_push(&type, OBJ_ARRAY, p->entry_data.data_size);
602 			do { char __c = '['; heap_obstack_grow(env, &__c, 1); } while(0);
603 			continue;
604 
605 		case MMDB_DATA_TYPE_UTF8_STRING:
606 			do { char __c = '"'; heap_obstack_grow(env, &__c, 1); } while(0);
607 			heap_obstack_grow(env, (char*)p->entry_data.utf8_string, p->entry_data.data_size);
608 			do { char __c = '"'; heap_obstack_grow(env, &__c, 1); } while(0);
609 			if (iskey)
610 				do { char __c = ':'; heap_obstack_grow(env, &__c, 1); } while(0);
611 			break;
612 
613 		case MMDB_DATA_TYPE_DOUBLE:
614 			heap_obstack_sprintf(env, "%g",p->entry_data.double_value);
615 			break;
616 
617 		case MMDB_DATA_TYPE_BYTES:
618 			do { char __c = '['; heap_obstack_grow(env, &__c, 1); } while(0);
619 			for (i = 0; i < p->entry_data.data_size; i++) {
620 				if (i) do { char __c = ','; heap_obstack_grow(env, &__c, 1); } while(0);
621 				heap_obstack_grow(env, "%d", p->entry_data.bytes[i]);
622 			}
623 			do { char __c = ']'; heap_obstack_grow(env, &__c, 1); } while(0);
624 			break;
625 
626 		case MMDB_DATA_TYPE_UINT16:
627 			heap_obstack_sprintf(env, "%u",p->entry_data.uint16);
628 			break;
629 
630 		case MMDB_DATA_TYPE_UINT32:
631 			heap_obstack_sprintf(env, "%" PRIu32,p->entry_data.uint32);
632 			break;
633 
634 		case MMDB_DATA_TYPE_INT32:
635 			heap_obstack_sprintf(env, "%" PRIi32,p->entry_data.int32);
636 			break;
637 
638 		case MMDB_DATA_TYPE_UINT64:
639 			heap_obstack_sprintf(env, "%" PRIu64,p->entry_data.uint64);
640 			break;
641 
642 		case MMDB_DATA_TYPE_UINT128:
643 
644 #line 347
645 do {
646 #line 347
647   char *__s = "'N/A";
648 #line 347
649   heap_obstack_grow(env, __s, strlen(__s));
650 #line 347
651 } while (0);//FIXME
652 			break;
653 
654 		case MMDB_DATA_TYPE_BOOLEAN:
655 
656 #line 351
657 do {
658 #line 351
659   char *__s = p->entry_data.boolean ? "true" : "false";
660 #line 351
661   heap_obstack_grow(env, __s, strlen(__s));
662 #line 351
663 } while (0);
664 			break;
665 
666 		case MMDB_DATA_TYPE_FLOAT:
667 			heap_obstack_sprintf(env, "%g",p->entry_data.float_value);
668 			break;
669 
670 		default:
671 			heap_obstack_cancel(env);
672 			free(indent_str);
673 			MMDB_free_entry_data_list(data_list);
674 			(
675 #line 362
676 	env_throw_bi(env, mfe_failure, "geoip2_get_json", _("unsupported MMDB data type %d"),p->entry_data.type)
677 #line 362
678 );
679 #line 365
680 		}
681 
682 		if (type) {
683 			iskey = !iskey;
684 			if (iskey == 1) {
685 				while (type && --type->count == 0) {
686 					if (indent_str) {
687 						do { char __c = '\n'; heap_obstack_grow(env, &__c, 1); } while(0);
688 						for (i = 1; i < type->level; i++)
689 
690 #line 374
691 do {
692 #line 374
693   char *__s = indent_str;
694 #line 374
695   heap_obstack_grow(env, __s, strlen(__s));
696 #line 374
697 } while (0);
698 					}
699 					do { char __c = type->type == OBJ_MAP
700 #line 376
701 							 ? '}' : ']'; heap_obstack_grow(env, &__c, 1); } while(0);
702 #line 378
703 					object_type_pop(&type);
704 				}
705 				if (type) {
706 					do { char __c = ','; heap_obstack_grow(env, &__c, 1); } while(0);
707 				}
708 			}
709 		}
710 	}
711 	do { char __c = 0; heap_obstack_grow(env, &__c, 1); } while(0);
712 	free(indent_str);
713 	MMDB_free_entry_data_list(data_list);
714 
715 	if (type) {
716 		while (type)
717 			object_type_pop(&type);
718 		(
719 #line 393
720 	env_throw_bi(env, mfe_failure, "geoip2_get_json", _("malformed data list: reported and actual number of keys differ"))
721 #line 393
722 );
723 #line 395
724 	}
725 
726 
727 #line 397
728 do {
729 #line 397
730   push(env, (STKVAL) (heap_obstack_finish(env)));
731 #line 397
732   goto endlab;
733 #line 397
734 } while (0);
735 }
736 endlab:
737 #line 399
738         env_function_cleanup_flush(env, NULL);
739 #line 399
740 	return;
741 #line 399
742 }
743 #line 982 "../../src/builtin/snarf.m4"
744 
745 #line 982
746 
747 #line 982
748 #endif /* WITH_GEOIP2 */
749 #line 982
750 
751 #line 982
752 void
753 #line 982
geoip2_init_builtin(void)754 geoip2_init_builtin(void)
755 #line 982
756 {
757 #line 982
758 
759 #line 982
760 #ifdef WITH_GEOIP2
761 #line 982
762 	pp_define("WITH_GEOIP2");
763 #line 982
764 	#line 58 "geoip2.bi"
765 GEOIP2_id = builtin_priv_register(geoip2_alloc, geoip2_destroy,
766 #line 58
767 NULL);
768 #line 78 "geoip2.bi"
769 va_builtin_install_ex("geoip2_dbname", bi_geoip2_dbname, 0, dtype_string, 0, 0, 0|0, dtype_unspecified);
770 #line 85 "geoip2.bi"
771 va_builtin_install_ex("geoip2_open", bi_geoip2_open, 0, dtype_unspecified, 1, 0, 0|0, dtype_string);
772 #line 147 "geoip2.bi"
773 va_builtin_install_ex("geoip2_get", bi_geoip2_get, 0, dtype_string, 2, 0, 0|0, dtype_string, dtype_string);
774 #line 237 "geoip2.bi"
775 va_builtin_install_ex("geoip2_get_json", bi_geoip2_get_json, 0, dtype_string, 2, 1, 0|0, dtype_string, dtype_number);
776 
777 #line 982 "../../src/builtin/snarf.m4"
778 
779 #line 982
780 #endif /* WITH_GEOIP2 */
781 #line 982
782 }
783 #line 982 "../../src/builtin/snarf.m4"
784 
785