Python-API: Inital commit of Python bindings for the VPP API.
[vpp.git] / vppapigen / node.c
1 /* 
2  *------------------------------------------------------------------
3  * node.c - the api generator's semantic back-end
4  *
5  * Copyright (c) 2004-2009 Cisco and/or its affiliates.
6  * Licensed under the Apache License, Version 2.0 (the "License");
7  * you may not use this file except in compliance with the License.
8  * You may obtain a copy of the License at:
9  *
10  *     http://www.apache.org/licenses/LICENSE-2.0
11  *
12  * Unless required by applicable law or agreed to in writing, software
13  * distributed under the License is distributed on an "AS IS" BASIS,
14  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15  * See the License for the specific language governing permissions and
16  * limitations under the License.
17  *------------------------------------------------------------------
18  */
19
20 #include <stdio.h>
21 #include <ctype.h>
22 #include <time.h>
23 #include <string.h>
24 #include <unistd.h>
25 #include <stdlib.h>
26 #include <vppinfra/vec.h>
27 #include <vppinfra/hash.h>
28
29 #include "lex.h"
30 #include "node.h"
31
32 #define YYSTYPE void *
33
34 FILE *ofp;
35 FILE *javafp;
36 FILE *jnifp;
37 FILE *pythonfp;
38 char *java_class;
39 time_t starttime;
40 char *vlib_app_name;
41 char *input_filename;
42 node_vft_t *the_vft[NODE_N_TYPES];
43 static int indent;
44 static int dont_output_version;
45 int dump_tree;
46 static char *fixed_name;
47 static char tmpbuf [MAXNAME];
48 static char *current_def_name;
49 static char *current_union_name;
50 static char *current_type_fmt;
51 static char *current_type_cast;
52 static char current_id;
53 static char current_is_complex;
54 static char *current_endianfun;
55 static char *current_type_name;
56 static int current_java_parameter_number;
57 static int current_java_emitted_parameter;
58 static int current_java_parameter_need_comma_space;
59 void *current_java_methodfun;
60 void *current_java_jnifun;
61
62 void indent_me(FILE *ofp)
63 {
64     int i;
65
66     for (i = 0; i < indent; i++)
67         putc(' ', ofp);
68 }
69
70 char *uppercase (char *s)
71 {
72     char *cp;
73
74     cp = tmpbuf;
75
76     while (*s && (cp < tmpbuf + (sizeof(tmpbuf)-1))) {
77         if (*s >= 'a' && *s <= 'z')
78             *cp++ = *s++ - ('a' - 'A');
79         else
80             *cp++ = *s++;
81     }
82     *cp = 0;
83     return(tmpbuf);
84 }
85
86 char *lowercase (char *s)
87 {
88     char *cp;
89
90     cp = tmpbuf;
91
92     while (*s && (cp < tmpbuf + (sizeof(tmpbuf)-1))) {
93         if (*s >= 'A' && *s <= 'Z')
94             *cp++ = *s++ + ('a' - 'A');
95         else
96             *cp++ = *s++;
97     }
98     *cp = 0;
99     return(tmpbuf);
100 }
101
102 /* 
103  * javah maps foo_bar to foo_1bar for whatever freakin' reason
104  * So, adjust java names accordingly.
105  */
106 char *java_name_mangle (void * name_arg)
107 {
108     char * name = name_arg;
109     static u8 * s;
110     int i;
111
112     vec_reset_length (s);
113
114     s = format (s, "%s%c", name, 0);
115
116     for (i = 0; i < vec_len(s); i++)
117         if (s[i] == '_') {
118             vec_delete (s, 1, i);
119             if (s[i] >= 'a' && s[i] <= 'z')
120                 s[i] -= ('a' - 'A');
121         }
122     vec_add1 (s, 0);
123     
124     return ((char *) s);
125 }
126
127 void primtype_recursive_print(node_t *this, i8 *fmt)
128 {
129     fputs((char *)fmt, stdout);
130
131     if (this->deeper) {
132         node_vft_t *vftp = the_vft[this->deeper->type];
133         vftp->print(this->deeper);
134     }
135 }
136
137 void primtype_recursive_generate(node_t *this, enum passid which, FILE *ofp,
138                                  i8 *type_name, i8 *type_fmt, i8 *type_cast)
139 {
140     node_vft_t *vftp;
141
142     current_type_name = (char *)type_name;
143     current_type_cast = (char *)type_cast;
144
145     switch(which) {
146     case TYPEDEF_PASS:
147         fputs((char *)type_name, ofp);
148         fputs(" ", ofp);
149         break;
150
151     case PRINTFUN_PASS:
152         current_type_fmt = (char *)type_fmt;
153         break;
154
155     case ENDIANFUN_PASS:
156         vftp = the_vft[this->type];
157         current_endianfun = vftp->endian_converter;
158         break;
159
160     case JAVA_METHOD_PASS:
161         vftp = the_vft[this->type];
162         current_java_methodfun = vftp->java_method_function;
163         break;
164
165     case PYTHON_PASS:
166         fputs("('", pythonfp);
167         fputs((char *)type_name, pythonfp);
168         fputs("', ", pythonfp);
169         break;
170
171     default:
172         fprintf(stderr, "primtype_recursive_generate: unimp pass %d\n", which);
173         break;
174     }
175
176     if (this->deeper) {
177         vftp = the_vft[this->deeper->type];
178         vftp->generate(this->deeper, which, ofp);
179     }
180 }
181
182 static int hidden_from_java(const node_t * deeper)
183 {
184     if (current_java_parameter_number++ < 3) {
185         if (!strncmp ((char *)(deeper->data[0]), "client_index", 12))
186             return 1;
187         else if (!strncmp ((char *)(deeper->data[0]), "context", 7))
188             return 1;
189         else if (!strncmp ((char *)(deeper->data[0]), "_vl_msg_id", 10))
190             return 1;
191     }
192
193     return 0;
194 }
195
196 void primtype_java_method (node_t * this, enum passid which, FILE *ofp, 
197                            char *java_type_name)
198 {
199     node_t * deeper;
200
201     deeper = this->deeper;
202
203     /* We'll take care of _msg_id, client_index, and context ourselves */
204     if (hidden_from_java(deeper)) {
205         return;
206     }
207
208     if (deeper->type == NODE_SCALAR)
209         fprintf (ofp, "%s %s", java_type_name, 
210                  java_name_mangle(deeper->data[0]));
211     else
212         fprintf (ofp, "%s [] %s", java_type_name, 
213                  java_name_mangle(deeper->data[0]));
214
215     current_java_emitted_parameter = 1;
216 }
217
218 void primtype_java_parameter (node_t * this, enum passid which, FILE *ofp, 
219                               char *java_type_name)
220 {
221     node_t * deeper;
222
223     deeper = this->deeper;
224
225     /* We'll take care of _msg_id, client_index, and context ourselves */
226     if (hidden_from_java(deeper)) {
227         return;
228     }
229     if (current_java_parameter_need_comma_space) {
230         current_java_parameter_need_comma_space = 0;
231         fputs (", ", ofp);
232     }
233
234     if (deeper->type == NODE_SCALAR)
235         fprintf (ofp, "%s %s", java_type_name, (char *)(deeper->data[0]));
236     else
237         fprintf (ofp, "%sArray %s", java_type_name, (char *)(deeper->data[0]));
238
239     current_java_emitted_parameter = 1;
240 }
241
242 void primtype_java_setup (node_t * this, enum passid which, FILE *ofp, 
243                           char *java_type_name, char *array_element_name)
244 {
245     node_t * deeper;
246
247     deeper = this->deeper;
248
249     /* We'll take care of _msg_id, client_index, and context ourselves */
250     if (hidden_from_java(deeper)) {
251         return;
252     }
253
254     if (deeper->type == NODE_VECTOR) {
255         indent_me(ofp);
256         fprintf (ofp, 
257                  "%s * %sP = (*env)->Get%sArrayElements (env, %s, NULL);\n",
258                  java_type_name, (char *)(deeper->data[0]),
259                  array_element_name, (char *)(deeper->data[0]));
260     }
261                  
262     current_java_emitted_parameter = 1;
263 }
264
265 void primtype_java_code (node_t * this, enum passid which, FILE *ofp, 
266                          char *java_type_name, char * swapper)
267 {
268     node_t * deeper;
269     char * s;
270
271     deeper = this->deeper;
272
273     /* We'll take care of _msg_id, client_index, and context ourselves */
274     if (hidden_from_java(deeper)) {
275         return;
276     }
277
278     indent_me(ofp);
279
280     s = (char *)(deeper->data[0]);
281
282     if (swapper == 0) {
283         if (deeper->type == NODE_VECTOR)
284             fprintf (ofp, "memcpy (mp->%s, %sP, sizeof (mp->%s));\n",
285                      s, s, s);
286         else
287             fprintf (ofp, "mp->%s = %s;\n", s, s);
288     } else {
289         if (deeper->type == NODE_VECTOR) {
290             fprintf(ofp, "{\n");
291             indent += 4;
292             indent_me(ofp);
293             fprintf(ofp, "int _i;\n");
294             indent_me(ofp);
295             fprintf(ofp, "for (_i = 0; _i < %u; _i++) {\n",
296                     (u64)(deeper->data[1]));
297             indent += 4;
298             indent_me(ofp);
299             fprintf(ofp, "mp->%s[_i] = %s(%sP[_i]);\n",
300                     s, swapper, s);
301             indent -= 4;
302             indent_me(ofp);
303             fprintf(ofp, "}\n");
304             indent -= 4;
305             indent_me(ofp);
306             fprintf(ofp, "}\n");
307         } else {
308             fprintf (ofp, "mp->%s = %s(%s);\n", s, swapper, s);
309         }
310     }
311
312     current_java_emitted_parameter = 1;
313 }
314
315 void primtype_java_teardown (node_t * this, enum passid which, FILE *ofp, 
316                              char * array_element_name)
317 {
318     node_t * deeper;
319
320     deeper = this->deeper;
321
322     /* We'll take care of _msg_id, client_index, and context ourselves */
323     if (hidden_from_java(deeper)) {
324         return;
325     }
326
327     if (deeper->type == NODE_VECTOR) {
328         indent_me(ofp);
329         fprintf (ofp, 
330                  "(*env)->Release%sArrayElements (env, %s, %sP, 0);\n",
331                  array_element_name, 
332                  (char *)(deeper->data[0]), 
333                  (char *)(deeper->data[0]));
334     }
335
336     current_java_emitted_parameter = 1;
337 }
338
339 void node_illegal_print (node_t *this)
340 {
341     fprintf(stderr, "node_illegal_print called\n");
342     exit(0);
343 }
344
345 void node_illegal_generate (node_t *this, enum passid notused, FILE *ofp)
346 {
347     fprintf(stderr, "node_illegal_generate called\n");
348     exit(0);
349 }
350
351 void node_illegal_java_method (node_t *this, enum passid notused, FILE *ofp)
352 {
353     fprintf(stderr, "node_illegal_java_method called\n");
354     exit(0);
355 }
356
357 void node_illegal_java_jni (node_t *this, enum passid notused, FILE *ofp)
358 {
359     fprintf(stderr, "node_illegal_java_jni called\n");
360     exit(0);
361 }
362
363 node_vft_t node_illegal_vft = {
364     node_illegal_print,
365     node_illegal_generate,
366     "illegal",
367     node_illegal_java_method,
368     node_illegal_java_jni,
369 };
370
371 void node_u8_print (node_t *this)
372 {
373     primtype_recursive_print(this, "u8 ");
374 }
375
376 void node_u8_generate (node_t *this, enum passid which, FILE *ofp)
377 {
378     primtype_recursive_generate(this, which, ofp, "u8", "%u", "(unsigned)");
379 }
380
381 void node_u8_java_method (node_t *this, enum passid which, FILE *ofp)
382 {
383     primtype_java_method (this, which, ofp, "byte");
384 }
385
386 void node_u8_java_parameter (node_t *this, enum passid which, FILE *ofp)
387 {
388     primtype_java_parameter (this, which, ofp, "jbyte");
389 }
390
391 void node_u8_java_setup (node_t *this, enum passid which, FILE *ofp)
392 {
393     primtype_java_setup (this, which, ofp, "jbyte", "Byte");
394 }
395
396 void node_u8_java_code (node_t *this, enum passid which, FILE *ofp)
397 {
398     primtype_java_code (this, which, ofp, "jbyte", 0 /* swapper */);
399 }
400
401 void node_u8_java_teardown (node_t *this, enum passid which, FILE *ofp)
402 {
403     primtype_java_teardown (this, which, ofp, "Byte");
404 }
405
406 node_vft_t node_u8_vft = {
407     node_u8_print,
408     node_u8_generate,
409     "", 
410     node_u8_java_method,
411     node_u8_java_parameter,
412     node_u8_java_setup,
413     node_u8_java_code,
414     node_u8_java_teardown,
415 };
416
417 void node_u16_print (node_t *this)
418 {
419     primtype_recursive_print(this, "u16 ");
420 }
421
422 void node_u16_generate (node_t *this, enum passid which, FILE *ofp)
423 {
424     primtype_recursive_generate(this, which, ofp, "u16", "%u", "(unsigned)");
425 }
426
427 void node_u16_java_method (node_t *this, enum passid which, FILE *ofp)
428 {
429     primtype_java_method (this, which, ofp, "short");
430 }
431
432 void node_u16_java_parameter (node_t *this, enum passid which, FILE *ofp)
433 {
434     primtype_java_parameter (this, which, ofp, "jshort");
435 }
436
437 void node_u16_java_setup (node_t *this, enum passid which, FILE *ofp)
438 {
439     primtype_java_setup (this, which, ofp, "jshort", "Short");
440 }
441
442 void node_u16_java_code (node_t *this, enum passid which, FILE *ofp)
443 {
444     primtype_java_code (this, which, ofp, "jshort", "clib_host_to_net_u16");
445 }
446
447 void node_u16_java_teardown (node_t *this, enum passid which, FILE *ofp)
448 {
449     primtype_java_teardown (this, which, ofp, "Short");
450 }
451
452 node_vft_t node_u16_vft = {
453     node_u16_print,
454     node_u16_generate,
455     "clib_net_to_host_u16",
456     node_u16_java_method,
457     node_u16_java_parameter,
458     node_u16_java_setup,
459     node_u16_java_code,
460     node_u16_java_teardown,
461 };
462
463 void node_u32_print (node_t *this)
464 {
465     primtype_recursive_print(this, "u32 ");
466 }
467
468 void node_u32_generate (node_t *this, enum passid which, FILE *ofp)
469 {
470     primtype_recursive_generate(this, which, ofp, "u32", "%u", "(unsigned)");
471 }
472
473 void node_u32_java_method (node_t *this, enum passid which, FILE *ofp)
474 {
475     primtype_java_method (this, which, ofp, "int");
476 }
477
478 void node_u32_java_parameter (node_t *this, enum passid which, FILE *ofp)
479 {
480     primtype_java_parameter (this, which, ofp, "jint");
481 }
482
483 void node_u32_java_setup (node_t *this, enum passid which, FILE *ofp)
484 {
485     primtype_java_setup (this, which, ofp, "jint", "Int");
486 }
487
488 void node_u32_java_code (node_t *this, enum passid which, FILE *ofp)
489 {
490     primtype_java_code (this, which, ofp, "jint", "clib_host_to_net_u32");
491 }
492
493 void node_u32_java_teardown (node_t *this, enum passid which, FILE *ofp)
494 {
495     primtype_java_teardown (this, which, ofp, "Int");
496 }
497
498 node_vft_t node_u32_vft = {
499     node_u32_print,
500     node_u32_generate,
501     "clib_net_to_host_u32",
502     node_u32_java_method,
503     node_u32_java_parameter,
504     node_u32_java_setup,
505     node_u32_java_code,
506     node_u32_java_teardown,
507 };
508
509 void node_u64_print (node_t *this)
510 {
511     primtype_recursive_print(this, "u64 ");
512 }
513
514 void node_u64_generate (node_t *this, enum passid which, FILE *ofp)
515 {
516     primtype_recursive_generate(this, which, ofp, "u64", "%llu", 
517                                 "(long long)");
518 }
519
520 void node_u64_java_method (node_t *this, enum passid which, FILE *ofp)
521 {
522     primtype_java_method (this, which, ofp, "long");
523 }
524
525 void node_u64_java_parameter (node_t *this, enum passid which, FILE *ofp)
526 {
527     primtype_java_parameter (this, which, ofp, "jlong");
528 }
529
530 void node_u64_java_setup (node_t *this, enum passid which, FILE *ofp)
531 {
532     primtype_java_setup (this, which, ofp, "jlong", "Long");
533 }
534
535 void node_u64_java_code (node_t *this, enum passid which, FILE *ofp)
536 {
537     primtype_java_code (this, which, ofp, "jlong", "clib_host_to_net_u64");
538 }
539
540 void node_u64_java_teardown (node_t *this, enum passid which, FILE *ofp)
541 {
542     primtype_java_teardown (this, which, ofp, "Long");
543 }
544
545 node_vft_t node_u64_vft = {
546     node_u64_print,
547     node_u64_generate,
548     "clib_net_to_host_u64",
549     node_u64_java_method,
550     node_u64_java_parameter,
551     node_u64_java_setup,
552     node_u64_java_code,
553     node_u64_java_teardown,
554 };
555
556 void node_i8_print (node_t *this)
557 {
558     primtype_recursive_print(this, "i8 ");
559 }
560
561 void node_i8_generate (node_t *this, enum passid which, FILE *ofp)
562 {
563     primtype_recursive_generate(this, which, ofp, "i8", "%d", "(int)");
564 }
565
566 node_vft_t node_i8_vft = {
567     node_i8_print,
568     node_i8_generate,
569     "",
570     node_u8_java_method,
571     node_u8_java_parameter,
572     node_u8_java_setup,
573     node_u8_java_code,
574     node_u8_java_teardown,
575 };
576
577 void node_i16_print (node_t *this)
578 {
579     primtype_recursive_print(this, "i16 ");
580 }
581
582 void node_i16_generate (node_t *this, enum passid which, FILE *ofp)
583 {
584     primtype_recursive_generate(this, which, ofp, "i16", "%d", "(int)");
585 }
586
587 node_vft_t node_i16_vft = {
588     node_i16_print,
589     node_i16_generate,
590     "clib_net_to_host_u16",
591     node_u16_java_method,
592     node_u16_java_parameter,
593     node_u16_java_setup,
594     node_u16_java_code,
595     node_u16_java_teardown,
596 };
597
598 void node_i32_print (node_t *this)
599 {
600     primtype_recursive_print(this, "i32 ");
601 }
602
603 void node_i32_generate (node_t *this, enum passid which, FILE *ofp)
604 {
605     primtype_recursive_generate(this, which, ofp, "i32", "%ld", "(long)");
606 }
607
608 node_vft_t node_i32_vft = {
609     node_i32_print,
610     node_i32_generate,
611     "clib_net_to_host_u32",
612     node_u32_java_method,
613     node_u32_java_parameter,
614     node_u32_java_setup,
615     node_u32_java_code,
616     node_u32_java_teardown,
617 };
618
619 void node_i64_print (node_t *this)
620 {
621     primtype_recursive_print(this, "i64 ");
622 }
623
624 void node_i64_generate (node_t *this, enum passid which, FILE *ofp)
625 {
626     primtype_recursive_generate(this, which, ofp, "i64", "%lld", 
627                                 "(long long)");
628 }
629
630 node_vft_t node_i64_vft = {
631     node_i64_print,
632     node_i64_generate,
633     "clib_net_to_host_u64",
634     node_u64_java_method,
635     node_u64_java_parameter,
636     node_u64_java_setup,
637     node_u64_java_code,
638     node_u64_java_teardown,
639 };
640
641 void node_f64_print (node_t *this)
642 {
643     primtype_recursive_print(this, "f64 ");
644 }
645
646 void node_f64_generate (node_t *this, enum passid which, FILE *ofp)
647 {
648     primtype_recursive_generate(this, which, ofp, "f64", "%.2f", 
649                                 "(double)");
650 }
651 void node_f64_java_method (node_t *this, enum passid which, FILE *ofp)
652 {
653     primtype_java_method (this, which, ofp, "double");
654 }
655
656 void node_f64_java_parameter (node_t *this, enum passid which, FILE *ofp)
657 {
658     primtype_java_parameter (this, which, ofp, "jdouble");
659 }
660
661 void node_f64_java_setup (node_t *this, enum passid which, FILE *ofp)
662 {
663     primtype_java_setup (this, which, ofp, "jdouble", "Double");
664 }
665
666 void node_f64_java_code (node_t *this, enum passid which, FILE *ofp)
667 {
668     /* 
669      * Current API code doesn't try to endian-swap doubles
670      * FP formats aren't portable yadda yadda yadda
671      */
672     primtype_java_code (this, which, ofp, "jdouble", 0 /* $$$ */);
673 }
674
675 void node_f64_java_teardown (node_t *this, enum passid which, FILE *ofp)
676 {
677     primtype_java_teardown (this, which, ofp, "Double");
678 }
679
680 node_vft_t node_f64_vft = {
681     node_f64_print,
682     node_f64_generate,
683     " ",                        /* FP numbers are sent in host byte order */
684     node_f64_java_method,
685     node_f64_java_parameter,
686     node_f64_java_setup,
687     node_f64_java_code,
688     node_f64_java_teardown,
689 };
690
691
692 void node_packed_print (node_t *this)
693 {
694     primtype_recursive_print (this, "packed ");
695 }
696
697 void node_packed_generate (node_t *this, enum passid which, FILE *ofp)
698 {
699     primtype_recursive_generate(this, which, ofp, "PACKED", "", "");
700 }
701
702 node_vft_t node_packed_vft = {
703     node_packed_print,
704     node_packed_generate,
705     0,
706 };
707
708 void node_define_print (node_t *this)
709 {
710     fprintf(stdout, "define %s {\n", CDATA0);
711     if (this->deeper) {
712         node_vft_t *vftp = the_vft[this->deeper->type];
713         fprintf(stdout, "    ");
714         vftp->print(this->deeper);
715     }
716     fprintf(stdout, "};\n");
717 }
718
719 static void emit_java_arg_declaration(node_t *child, FILE *fp) {
720     current_java_parameter_number = 0;
721     while (child) {
722         node_vft_t *vftp = the_vft[child->type];
723         current_java_emitted_parameter = 0;
724         vftp->java_method_function(child, JAVA_METHOD_PASS, fp);
725         child = child->peer;
726         if (child && current_java_emitted_parameter)
727             fputs (", ", fp);
728     }
729 }
730
731 void node_define_generate (node_t *this, enum passid which, FILE *fp)
732 {
733     node_t *child, *save_child;
734
735     switch(which) {
736     case TYPEDEF_PASS:
737         fprintf(fp, "typedef VL_API_PACKED(struct _vl_api_%s {\n", CDATA0);
738         child = this->deeper;
739         indent += 4;
740         while (child) {
741             node_vft_t *vftp = the_vft[child->type];
742             indent_me(fp);
743             vftp->generate(child, which, fp);
744             child = child->peer;
745         }
746         indent -= 4;
747         fprintf(fp, "}) vl_api_%s_t;\n\n", CDATA0);
748         break;
749
750     case ENDIANFUN_PASS:
751     case PRINTFUN_PASS:
752         child = this->deeper;
753         while (child) {
754             node_vft_t *vftp = the_vft[child->type];
755             vftp->generate(child, which, fp);
756             child = child->peer;
757         }
758         break;
759
760     case JAVA_METHOD_PASS:
761         indent += 4;
762         indent_me(fp);
763
764         /* Generate private native declaration */
765         fprintf (fp, "private static native int %s0(", java_name_mangle(CDATA0));
766         emit_java_arg_declaration(this->deeper, fp);
767         fputs (");\n", fp);
768
769         /* Generate public Java method */
770         indent_me(fp);
771         fprintf (fp, "public final int %s(", java_name_mangle(CDATA0));
772         emit_java_arg_declaration(this->deeper, fp);
773         fputs (") {\n", fp);
774
775         indent += 4;
776         indent_me(fp);
777         fputs ("checkConnected();\n", fp);
778         indent_me(fp);
779         fprintf (fp, "return %s.%s0(", java_class, java_name_mangle(CDATA0));
780
781         child = this->deeper;
782         current_java_parameter_number = 0;
783         while (child && hidden_from_java(child->deeper)) {
784             child = child->peer;
785         }
786         while (child) {
787             fputs(java_name_mangle((char *)(child->deeper->data[0])), fp);
788             child = child->peer;
789             if (child)
790                 fputs (", ", fp);
791         }
792
793         fputs (");\n", fp);
794         indent -= 4;
795         indent_me(fp);
796         fputs ("}\n\n", fp);
797         indent -= 4;
798         break;
799
800     case JAVA_JNI_PASS:
801         /* Generate function prototype */
802         fprintf (fp, "JNIEXPORT jint JNICALL Java_org_openvpp_vppjapi_%s_%s0\n", 
803                  java_class, java_name_mangle(CDATA0));
804
805         fprintf (fp, "(JNIEnv * env, jclass clazz");
806         current_java_parameter_need_comma_space = 1;
807         child = this->deeper;
808         save_child = child;
809         while (child) {
810             node_vft_t *vftp = the_vft[child->type];
811             current_java_emitted_parameter = 0;
812             vftp->java_jni_parameter(child, which, fp);
813             child = child->peer;
814             if (child && current_java_emitted_parameter)
815                 fputs (", ", fp);
816         }
817         fprintf (fp, ")\n{\n");
818         indent += 4;
819
820         /* define the api message pointer */
821         indent_me(fp);
822         fprintf (fp, "vppjni_main_t *jm = &vppjni_main;\n");
823         indent_me(fp);
824         fprintf (fp, "vl_api_%s_t * mp;\n", current_def_name);
825         indent_me(fp);
826         fprintf (fp, "u32 my_context_id;\n");
827         indent_me(fp);
828         fprintf (fp, "int rv;\n");
829
830         indent_me(fp);
831         fprintf (fp, "rv = vppjni_sanity_check (jm);\n");
832         indent_me(fp);
833         fprintf (fp, "if (rv) return rv;\n");
834
835         indent_me(fp);
836         fprintf (fp, "my_context_id = vppjni_get_context_id (jm);\n");
837
838         /* Generate array setups, if any */
839         child = save_child;
840         while (child) {
841             node_vft_t *vftp = the_vft[child->type];
842             current_java_parameter_number = 0;
843             current_java_emitted_parameter = 0;
844             vftp->java_jni_setup(child, which, fp);
845             child = child->peer;
846         }
847
848         /* Setup the API message */
849         indent_me(fp);
850         fprintf (fp, "M(%s, %s);\n", uppercase(current_def_name),
851                  current_def_name);
852         indent_me(fp);
853         fprintf (fp, "mp->context = clib_host_to_net_u32 (my_context_id);\n");
854         /* $$$ Set up context hash table or some such... */
855
856         /* Generate code */
857         child = save_child;
858         while (child) {
859             node_vft_t *vftp = the_vft[child->type];
860             current_java_parameter_number = 0;
861             current_java_emitted_parameter = 0;
862             vftp->java_jni_code(child, which, fp);
863             child = child->peer;
864         }
865
866         /* Generate array teardowns */
867         child = save_child;
868         while (child) {
869             node_vft_t *vftp = the_vft[child->type];
870             current_java_parameter_number = 0;
871             current_java_emitted_parameter = 0;
872             vftp->java_jni_teardown(child, which, fp);
873             child = child->peer;
874         }
875
876         /* Send the message, return context_id */
877         indent_me (fp);
878         fprintf (fp, "S;\n");
879         indent_me (fp);
880         fprintf (fp, "return my_context_id;\n");
881         
882         indent -= 4;
883         fprintf (fp, "}\n\n");
884         break;
885
886     case PYTHON_PASS:
887       fprintf(fp, "('%s',\n", CDATA0);
888         child = this->deeper;
889         indent += 4;
890         while (child) {
891             node_vft_t *vftp = the_vft[child->type];
892             indent_me(fp);
893             vftp->generate(child, which, fp);
894             child = child->peer;
895         }
896         indent -= 4;
897         fprintf(fp, "),\n\n");
898         break;
899
900     default:
901         fprintf(stderr, "node_define_generate: unimp pass %d\n", which);
902         break;
903     }
904 }
905
906 node_vft_t node_define_vft = {
907     node_define_print,
908     node_define_generate,
909     0,
910 };
911
912 void node_union_print (node_t *this)
913 {
914     primtype_recursive_print (this, "union ");
915 }
916
917 void node_union_generate (node_t *this, enum passid which, FILE *fp)
918 {
919     node_t *child;
920     node_t *uelem;
921     int case_id=1;
922
923     switch(which) {
924     case TYPEDEF_PASS:
925         fprintf(fp, "u8 _%s_which;\n", CDATA0);
926         indent_me(fp);
927         fprintf(fp, "union _%s {\n", CDATA0);
928         child = this->deeper;
929         indent += 4;
930     
931         while (child) {
932             node_vft_t *vftp = the_vft[child->type];
933             indent_me(fp);
934             vftp->generate(child, which, fp);
935             child = child->peer;
936         }
937         indent -= 4;
938         indent_me(fp);
939         fprintf(fp, "} %s;\n", CDATA0);
940         break;
941
942     case PRINTFUN_PASS:
943     case ENDIANFUN_PASS:
944         uelem = this->deeper;
945         
946         indent_me(fp);
947         fprintf(fp, "switch(a->_%s_which) {\n",
948                 CDATA0);
949         indent += 4;
950         current_union_name = CDATA0;
951
952         /* Walk the list of objects in this union */
953         while (uelem) {
954             node_vft_t *vftp = the_vft[uelem->type];
955             indent -= 4;
956             indent_me(fp);
957             fprintf(fp, "case %d:\n", case_id);
958             case_id++;
959             indent += 4;
960             /* Drill down on each element */
961             vftp->generate(uelem, which, fp);
962             indent_me(fp);
963             fprintf(fp, "break;\n");
964             uelem = uelem->peer;
965         }
966         current_union_name = 0;
967         indent -= 4;
968         indent_me(fp);
969         fprintf(fp, "default:\n");
970         indent += 4;
971         indent_me(fp);                 
972         if (which == PRINTFUN_PASS) {
973             fprintf(fp, 
974                     "vl_print(handle, \"WARNING: _%s_which not set.\\n\");\n",
975                     CDATA0);
976         }
977         indent_me(fp);
978         fprintf(fp, "break;\n");
979         indent -= 4;
980         indent_me(fp);
981         fprintf(fp, "}\n");
982         break;
983
984     default:
985         fprintf(stderr, "node_union_generate: unimp pass %d\n", which);
986         break;
987     }
988 }
989
990
991 node_vft_t node_union_vft = {
992     node_union_print,
993     node_union_generate,
994     0,
995 };
996
997 void node_scalar_print (node_t *this)
998 {
999     fprintf(stdout, "%s", CDATA0);
1000     primtype_recursive_print (this, "");
1001 }
1002
1003 void node_scalar_generate (node_t *this, enum passid which, FILE *fp)
1004 {
1005     char *union_prefix = "";
1006
1007     if (current_union_name) {
1008         sprintf(tmpbuf, "%s.", current_union_name);
1009         union_prefix = tmpbuf;
1010     }
1011
1012     switch(which) {
1013     case TYPEDEF_PASS:
1014         fprintf(fp, "%s;\n", CDATA0);
1015         break;
1016
1017     case PRINTFUN_PASS:
1018         indent_me(fp);
1019         if (current_is_complex) {
1020             fprintf(fp, "vl_api_%s_t_print(a->%s%s, handle);\n", 
1021                     current_type_name, union_prefix, CDATA0);
1022         } else {
1023             if (!strcmp(current_type_fmt, "uword")) {
1024                 fprintf(fp, 
1025            "vl_print(handle, \"%s%s: \" _uword_fmt \"\\n\", %s a->%s%s);\n", 
1026                         union_prefix, CDATA0, "(_uword_cast)",
1027                         union_prefix, CDATA0);
1028             } else {
1029                 fprintf(fp, 
1030                         "vl_print(handle, \"%s%s: %s\\n\", %s a->%s%s);\n", 
1031                         union_prefix, CDATA0, 
1032                         current_type_fmt, current_type_cast,
1033                         union_prefix, CDATA0);
1034             }
1035         }
1036         break;
1037
1038     case ENDIANFUN_PASS:
1039         indent_me(fp);
1040         if (current_is_complex) {
1041             fprintf(fp, "vl_api%s_t_endian(a->%s%s);\n", 
1042                     current_type_name, union_prefix, CDATA0);
1043         } else {
1044             /* Current_endianfun == NULL means e.g. it's a u8... */
1045             if (current_endianfun) {
1046                 fprintf(fp, "a->%s%s = %s(a->%s%s);\n", union_prefix,
1047                         CDATA0, current_endianfun, 
1048                         union_prefix, CDATA0);
1049             } else {
1050                 fprintf(fp, "/* a->%s%s = a->%s%s */\n",
1051                         union_prefix, CDATA0, 
1052                         union_prefix, CDATA0);
1053             }
1054         }
1055         break;
1056     case PYTHON_PASS:
1057         fprintf(fp, "'%s'),\n", CDATA0);
1058         break;
1059
1060     default:
1061         fprintf(stderr, "node_scalar_generate: unimp pass %d\n", which);
1062     }
1063     if (this->deeper) {
1064         fprintf(stderr, "broken recursion in node_scalar_generate\n");
1065     }
1066 }
1067
1068
1069 node_vft_t node_scalar_vft = {
1070     node_scalar_print,
1071     node_scalar_generate,
1072     0,
1073 };
1074
1075 void node_vector_print (node_t *this)
1076 {
1077     primtype_recursive_print (this, "vector ");
1078 }
1079
1080 void node_vector_generate (node_t *this, enum passid which, FILE *fp)
1081 {
1082     char *union_prefix = "";
1083
1084     if (current_union_name) {
1085         sprintf(tmpbuf, "%s.", current_union_name);
1086         union_prefix = tmpbuf;
1087     }
1088
1089     switch(which) {
1090     case TYPEDEF_PASS:
1091         fprintf(fp, "%s[%d];\n", CDATA0, IDATA1);
1092         break;
1093
1094     case PRINTFUN_PASS:
1095         /* Don't bother about "u8 data [0];" et al. */
1096         if (IDATA1 == 0)
1097             break;
1098
1099         indent_me(fp);
1100         fprintf(fp, "{\n");
1101         indent += 4;
1102         indent_me(fp);
1103         fprintf(fp, "int _i;\n");
1104         indent_me(fp);
1105         fprintf(fp, "for (_i = 0; _i < %d; _i++) {\n", 
1106                 IDATA1);
1107         indent += 4;
1108         indent_me(fp);
1109         if (current_is_complex) {
1110             fprintf(fp, "vl_print(handle, \"%s%s[%%d]: ",
1111                     union_prefix, CDATA0);
1112             fprintf(fp, 
1113                     "vl_print_%s (handle, a->%s%s[_i]);\n", 
1114                     CDATA0, union_prefix, CDATA0);
1115         } else {
1116             fprintf(fp, 
1117          "vl_print(handle, \"%s%s[%%d]: %s\\n\", _i, a->%s%s[_i]);\n",
1118                     union_prefix, CDATA0, 
1119                     current_type_fmt, 
1120                     union_prefix, CDATA0);
1121         }
1122         indent -= 4;
1123         indent_me(fp);
1124         fprintf(fp, "}\n");
1125         indent -= 4;
1126         indent_me(fp);
1127         fprintf(fp, "}\n");
1128         break;
1129
1130     case ENDIANFUN_PASS:
1131         /* Don't bother about "u8 data [0];" et al. */
1132         if (IDATA1 == 0)
1133             break;
1134
1135         indent_me(fp);
1136         fprintf(fp, "{\n");
1137         indent += 4;
1138         indent_me(fp);
1139         fprintf(fp, "int _i;\n");
1140         indent_me(fp);
1141         fprintf(fp, "for (_i = 0; _i < %d; _i++) {\n", 
1142                 IDATA1);
1143         indent += 4;
1144         indent_me(fp);
1145         if (current_is_complex) {
1146             fprintf(fp, 
1147                     "vl_api_%s_t_endian (a->%s%s[_i]);\n", 
1148                     current_type_name, union_prefix, CDATA0);
1149         } else {
1150             fprintf(fp, 
1151                     "a->%s%s[_i] = %s(a->%s%s[_i]);\n", 
1152                     union_prefix, CDATA0, 
1153                     current_endianfun, 
1154                     union_prefix, CDATA0);
1155         }
1156         indent -= 4;
1157         indent_me(fp);
1158         fprintf(fp, "}\n");
1159         indent -= 4;
1160         indent_me(fp);
1161         fprintf(fp, "}\n");
1162         break;
1163     case PYTHON_PASS:
1164         fprintf(fp, "'%s', '%d'),\n", CDATA0, IDATA1);
1165         break;
1166
1167     default:
1168         fprintf(stderr, "node_vector_generate: unimp pass %d\n", which);
1169     }
1170     if (this->deeper) {
1171         fprintf(stderr, "broken recursion in node_vector_generate\n");
1172     }
1173 }
1174
1175 node_vft_t node_vector_vft = {
1176     node_vector_print,
1177     node_vector_generate,
1178     0,
1179 };
1180
1181 void node_complex_print (node_t *this)
1182 {
1183     primtype_recursive_print (this, "complex ");
1184 }
1185
1186 void node_complex_generate (node_t *this, enum passid which, FILE *fp)
1187 {
1188     node_t *deeper;
1189     node_vft_t *vftp;
1190     char *member_name = "broken!";
1191     char *union_prefix = "";
1192
1193     if (current_union_name) {
1194         sprintf(tmpbuf, "%s.", current_union_name);
1195         union_prefix = tmpbuf;
1196     }
1197
1198     current_is_complex++;
1199     
1200     switch(which) {
1201     case TYPEDEF_PASS:
1202         fprintf(fp, "%s ", CDATA0);
1203         deeper = this->deeper;
1204         if (deeper) {
1205             vftp = the_vft[deeper->type];
1206             vftp->generate(deeper, which, fp);
1207         }
1208         break;
1209
1210     case PRINTFUN_PASS:
1211         deeper = this->deeper;
1212         while (deeper) {
1213             if (deeper->type == NODE_SCALAR ||
1214                 deeper->type == NODE_VECTOR) {
1215                 member_name = deeper->data[0];
1216                 break;
1217             }
1218             deeper = deeper->deeper;
1219         }
1220         indent_me(fp);
1221         fprintf(fp, "vl_print(handle, \"%s%s ----- \\n\");\n", 
1222                 union_prefix, member_name);
1223         indent_me(fp);
1224         fprintf(fp, "%s_print(&a->%s%s, handle);\n", 
1225                 CDATA0, union_prefix, member_name);
1226         indent_me(fp);
1227         fprintf(fp, "vl_print(handle, \"%s%s ----- END \\n\");\n", 
1228                 union_prefix, member_name);
1229         break;
1230
1231     case ENDIANFUN_PASS:
1232         deeper = this->deeper;
1233         while (deeper) {
1234             if (deeper->type == NODE_SCALAR ||
1235                 deeper->type == NODE_VECTOR) {
1236                 member_name = deeper->data[0];
1237                 break;
1238             }
1239             deeper = deeper->deeper;
1240         }
1241
1242         indent_me(fp);
1243         fprintf(fp, "%s_endian(&a->%s%s);\n", 
1244                 CDATA0, union_prefix, member_name);
1245         break;
1246     case PYTHON_PASS:
1247         fprintf(fp, "('%s',", CDATA0);
1248         deeper = this->deeper;
1249         if (deeper) {
1250             vftp = the_vft[deeper->type];
1251             vftp->generate(deeper, which, fp);
1252         }
1253         break;
1254
1255     default:
1256         fprintf(stderr, "node_complex_generate unimp pass %d...\n", which);
1257         break;
1258     }
1259     current_is_complex--;
1260 }
1261
1262 node_vft_t node_complex_vft = {
1263     node_complex_print,
1264     node_complex_generate,
1265     0,
1266 };
1267
1268 void node_noversion_print (node_t *this)
1269 {
1270     primtype_recursive_print (this, "noversion ");
1271 }
1272
1273 void node_noversion_generate (node_t *this, enum passid which, FILE *ofp)
1274 {
1275     fprintf(stderr, "node_noversion_generate called...\n");
1276 }
1277
1278 node_vft_t node_noversion_vft = {
1279     node_noversion_print,
1280     node_noversion_generate,
1281     0,
1282 };
1283
1284 void node_uword_print (node_t *this)
1285 {
1286     primtype_recursive_print(this, "uword ");
1287 }
1288
1289 void node_uword_generate (node_t *this, enum passid which, FILE *ofp)
1290 {
1291     primtype_recursive_generate(this, which, ofp, "uword", "uword", "");
1292 }
1293
1294 node_vft_t node_uword_vft = {
1295     node_uword_print,
1296     node_uword_generate,
1297     "clib_net_to_host_uword",
1298 };
1299
1300 node_vft_t *the_vft[NODE_N_TYPES] = {
1301     &node_illegal_vft,
1302     &node_u8_vft,
1303     &node_u16_vft,
1304     &node_u32_vft,
1305     &node_u64_vft,
1306     &node_i8_vft,
1307     &node_i16_vft,
1308     &node_i32_vft,
1309     &node_i64_vft,
1310     &node_f64_vft,
1311     &node_packed_vft,
1312     &node_define_vft,
1313     &node_union_vft,
1314     &node_scalar_vft,
1315     &node_vector_vft,
1316     &node_complex_vft,
1317     &node_noversion_vft,
1318     &node_uword_vft,
1319 };
1320
1321 void *make_node (enum node_subclass type)
1322 {
1323     node_t *rv;
1324
1325     rv = (node_t *) malloc (sizeof (*rv));
1326     if (rv == 0) {
1327         fprintf (stderr, "fatal: make_node out of memory\n");
1328         exit (1);
1329     }
1330     bzero (rv, sizeof (*rv));
1331     rv->type = type;
1332     return ((void *) rv);
1333 }
1334
1335 YYSTYPE deeper (YYSTYPE arg1, YYSTYPE arg2)
1336 {
1337     node_t *np1 = (node_t *) arg1;
1338     node_t *np2 = (node_t *) arg2;
1339     node_t *hook_point;
1340     
1341     hook_point = np1;
1342
1343     while (hook_point->deeper)
1344         hook_point = hook_point->deeper;
1345
1346     hook_point->deeper = np2;
1347     return (arg1);
1348 }
1349
1350 YYSTYPE addpeer (YYSTYPE arg1, YYSTYPE arg2)
1351 {
1352     node_t *np1 = (node_t *) arg1;
1353     node_t *np2 = (node_t *) arg2;
1354     node_t *hook_point;
1355     
1356     hook_point = np1;
1357
1358     while (hook_point->peer)
1359         hook_point = hook_point->peer;
1360
1361     hook_point->peer = np2;
1362     return (arg1);
1363 }
1364
1365 /*
1366  * add_slist (stmt_list, stmt)
1367  */
1368
1369 YYSTYPE add_slist (YYSTYPE a1, YYSTYPE a2)
1370 {
1371     if (a1 && a2)
1372         return (addpeer(a1, a2));
1373     else if(a1)
1374         return(a1);
1375     else 
1376         return(a2);
1377 }
1378
1379 /*
1380  * add_define (char *name, defn_list);
1381  */
1382 YYSTYPE add_define (YYSTYPE a1, YYSTYPE a2)
1383 {
1384     node_t *np;
1385
1386     np = make_node(NODE_DEFINE);
1387     np->data[0] = a1;
1388     deeper((YYSTYPE)np, a2);
1389     return ((YYSTYPE) np);
1390 }
1391
1392 /*
1393  * add_defbody (defn_list, new_defn)
1394  */
1395 YYSTYPE add_defbody (YYSTYPE a1, YYSTYPE a2)
1396 {
1397     return (addpeer(a1, a2));
1398 }
1399
1400 /*
1401  * add_primtype ([packed], primitive type, instance)
1402  */ 
1403
1404 YYSTYPE add_primtype (YYSTYPE a1, YYSTYPE a2, YYSTYPE a3)
1405 {
1406     node_t *np1;
1407
1408     np1 = (node_t *)a1;
1409     
1410     /* Hook instance to type node */
1411     deeper (a1, a2);
1412     if (a3) {
1413         deeper(a1, a3);
1414     }
1415     return (a1);
1416 }
1417
1418 /*
1419  * add_complex(char *type_name, instance)
1420  */
1421
1422 YYSTYPE add_complex (YYSTYPE a1, YYSTYPE a2)
1423 {
1424     node_t *np;
1425
1426     np = make_node(NODE_COMPLEX);
1427     np->data[0] = (void *) a1;
1428
1429     deeper((YYSTYPE)np, a2);
1430     return ((YYSTYPE) np);
1431 }
1432
1433 /*
1434  * add_union(char *type_name, definition)
1435  */
1436
1437 YYSTYPE add_union (YYSTYPE a1, YYSTYPE a2)
1438 {
1439     node_t *np;
1440
1441     np = make_node(NODE_UNION);
1442     np->data[0] = (void *) a1;
1443
1444     deeper((YYSTYPE)np, a2);
1445     return ((YYSTYPE) np);
1446 }
1447
1448
1449 /*
1450  * add_vector_vbl (node_t *variable, YYSTYPE size)
1451  */
1452
1453 YYSTYPE add_vector_vbl (YYSTYPE a1, YYSTYPE a2)
1454 {
1455     node_t *np;
1456
1457     np = make_node(NODE_VECTOR);
1458     np->data[0] = (void *) a1;
1459     np->data[1] = (void *) a2;
1460     return ((YYSTYPE) np);
1461 }
1462
1463 /*
1464  * add_scalar_vbl (char *name)
1465  */
1466 YYSTYPE add_scalar_vbl (YYSTYPE a1)
1467 {
1468     node_t *np;
1469
1470     np = make_node(NODE_SCALAR);
1471     np->data[0] = (void *) a1;
1472     return ((YYSTYPE) np);
1473 }
1474
1475 /*
1476  * set_flags (int flags, msg(=0?))
1477  */ 
1478 YYSTYPE set_flags(YYSTYPE a1, YYSTYPE a2)
1479 {
1480     node_t *np;
1481     int flags;
1482
1483     np = (node_t *)a2;
1484     if (!np)
1485         return(0);
1486
1487     flags = (int)(uword) a1;
1488
1489     np->flags |= flags;
1490     return (a2);
1491 }
1492 /*
1493  * suppress_version
1494  */
1495 YYSTYPE suppress_version (void)
1496 {
1497     dont_output_version = 1;
1498     return (0);
1499 }
1500
1501 void dump(node_t *np)
1502 {
1503     node_vft_t *vftp;
1504
1505     while (np) {
1506         vftp = the_vft[np->type];
1507         vftp->print(np);
1508         np = np->peer;
1509     }
1510 }
1511
1512 char *fixup_input_filename(void)
1513 {
1514     char *cp;
1515
1516     cp = (char *)input_filename;
1517
1518     while (*cp)
1519         cp++;
1520
1521     cp--;
1522
1523     while (cp > input_filename && *cp != '/')
1524         cp--;
1525     if (*cp == '/')
1526         cp++;
1527
1528     strcpy (tmpbuf, cp);
1529
1530     cp = tmpbuf;
1531
1532     while (*cp)
1533         cp++;
1534
1535     cp--;
1536
1537     while (cp > tmpbuf && *cp != '.')
1538         cp--;
1539     
1540     if (*cp == '.')
1541         *cp = 0;
1542
1543     return (sxerox(tmpbuf));
1544 }
1545
1546 void generate_top_boilerplate(FILE *fp)
1547
1548 {
1549     char *datestring = ctime(&starttime);
1550     fixed_name = fixup_input_filename();
1551
1552     datestring[24] = 0;
1553
1554     fprintf (fp, "/*\n");
1555     fprintf (fp, " * VLIB API definitions %s\n", datestring);
1556     fprintf (fp, " * Input file: %s\n", input_filename);
1557     fprintf (fp, " * Automatically generated: please edit the input file ");
1558     fprintf (fp, "NOT this file!\n");
1559
1560     /* Moron Acme trigger workaround */
1561     fprintf (fp, " * %syright (c) %s by Cisco Systems, Inc.\n", "Cop", 
1562              &datestring[20]);
1563     fprintf (fp, " */\n\n");
1564     fprintf (fp, "#if defined(vl_msg_id)||defined(vl_union_id)||");
1565     fprintf (fp, "defined(vl_printfun) \\\n ||defined(vl_endianfun)||");
1566     fprintf (fp, " defined(vl_api_version)||defined(vl_typedefs) \\\n");
1567     fprintf (fp, " ||defined(vl_msg_name)\n");
1568     fprintf (fp, "/* ok, something was selected */\n");
1569     fprintf (fp, "#else\n");
1570     fprintf (fp, "#warning no content included from %s\n", input_filename);
1571     fprintf (fp, "#endif\n\n");
1572     fprintf (fp, "#define VL_API_PACKED(x) x __attribute__ ((packed))\n\n");
1573 }
1574
1575 void generate_bottom_boilerplate(FILE *fp)
1576
1577 {
1578     fprintf (fp, "\n#ifdef vl_api_version\n");
1579
1580     if (dont_output_version) {
1581         fprintf (fp, "/* WARNING: API FILE VERSION CHECK DISABLED */\n");
1582         input_crc = 0;
1583     }
1584
1585     fprintf (fp, "vl_api_version(%s, 0x%08x)\n\n", 
1586              fixed_name, (unsigned int)input_crc);
1587     fprintf (fp, "#endif\n\n");
1588 }
1589
1590 void generate_msg_ids(YYSTYPE a1, FILE *fp)
1591 {
1592     node_t *np = (node_t *)a1;
1593
1594     fprintf (fp, "\n/****** Message ID / handler enum ******/\n\n");
1595     fprintf (fp, "#ifdef vl_msg_id\n");
1596
1597     while (np) {
1598         if (np->type == NODE_DEFINE) {
1599             if (!(np->flags & NODE_FLAG_TYPEONLY)) {
1600                 fprintf (fp, "vl_msg_id(VL_API_%s, vl_api_%s_t_handler)\n", 
1601                          uppercase(np->data[0]), (i8 *)np->data[0]);
1602             } else {
1603                 fprintf (fp, "/* typeonly: %s */\n", (i8 *)np->data[0]);
1604             }
1605         }
1606         np = np->peer;
1607     }
1608     fprintf (fp, "#endif\n");
1609
1610 }
1611
1612 void generate_msg_names(YYSTYPE a1, FILE *fp)
1613 {
1614     node_t *np = (node_t *)a1;
1615
1616     fprintf (fp, "\n/****** Message names ******/\n\n");
1617
1618     fprintf (fp, "#ifdef vl_msg_name\n");
1619
1620     while (np) {
1621         if (np->type == NODE_DEFINE) {
1622             if (!(np->flags & NODE_FLAG_TYPEONLY)) {
1623                 fprintf (fp, "vl_msg_name(vl_api_%s_t, %d)\n",
1624                          (i8 *) np->data[0], 
1625                          (np->flags & NODE_FLAG_DONT_TRACE ? 0 : 1));
1626             } else {
1627                 fprintf (fp, "/* typeonly: %s */\n", (i8 *)np->data[0]);
1628             }
1629         }
1630         np = np->peer;
1631     }
1632     fprintf (fp, "#endif\n\n");
1633 }
1634
1635 void generate_typedefs(YYSTYPE a1, FILE *fp)
1636 {
1637     node_t *np = (node_t *)a1;
1638     node_vft_t *vftp;
1639
1640     fprintf(fp, "\n/****** Typedefs *****/\n\n");
1641     fprintf(fp, "#ifdef vl_typedefs\n\n");
1642
1643     /* Walk the top-level node-list */
1644     while (np) {
1645         if (np->type == NODE_DEFINE) {
1646             /* Yeah, this is pedantic */
1647             vftp = the_vft[np->type];
1648             vftp->generate(np, TYPEDEF_PASS, fp);
1649         }
1650         np = np->peer;
1651     }
1652     fprintf(fp, "#endif /* vl_typedefs */\n\n");
1653 }
1654
1655 void union_walk_one_defn(node_t *np, FILE *fp)
1656 {
1657     node_t *vblp;
1658     node_t *uelem;
1659
1660     /* Walk the list of typed objects in this msg def */
1661     while (np) {
1662         if (np->type == NODE_UNION) {
1663             current_union_name = np->data[0];
1664             uelem = np->deeper;
1665
1666             /* Walk the list of objects in this union */
1667             while (uelem) {
1668                 vblp = uelem->deeper;
1669                 /* Drill down on each element, find the variable name */
1670                 while(vblp) {
1671                     if (vblp->type == NODE_SCALAR ||
1672                         vblp->type == NODE_VECTOR ||
1673                         vblp->type == NODE_COMPLEX) {
1674                         fprintf(ofp, "#define %s_", 
1675                                 uppercase(current_def_name));
1676                         fprintf(ofp, "%s_", uppercase(current_union_name));
1677                         fprintf(ofp, "%s %d\n",uppercase(vblp->data[0]),
1678                                 current_id);
1679                         current_id++;
1680                         break;
1681                     }
1682                     vblp = vblp->deeper;
1683                 }
1684                 uelem = uelem->peer;
1685             }
1686             current_union_name = 0;
1687             current_id = 1;
1688         }
1689         np = np->peer;
1690     }
1691 }
1692
1693 void generate_uniondefs(YYSTYPE a1, FILE *fp)
1694 {
1695     node_t *np = (node_t *)a1;
1696
1697     fprintf(fp, "/****** Discriminated Union Definitions *****/\n\n");
1698     fprintf(fp, "#ifdef vl_union_id\n\n");
1699
1700     /* Walk the top-level node-list */
1701     while (np) {
1702         if (np->type == NODE_DEFINE) {
1703             current_id = 1;
1704             current_def_name = np->data[0];
1705             union_walk_one_defn(np->deeper, fp);
1706         }
1707         np = np->peer;
1708     }
1709     fprintf(fp, "\n#endif /* vl_union_id */\n\n");
1710 }
1711
1712 void generate_printfun(YYSTYPE a1, FILE *fp)
1713 {
1714     node_t *np = (node_t *)a1;
1715     node_vft_t *vftp;
1716
1717     fprintf(fp, "/****** Print functions *****/\n\n");
1718     fprintf(fp, "#ifdef vl_printfun\n\n");
1719
1720     fprintf(fp, "#ifdef LP64\n");
1721     fputs ("#define _uword_fmt \"%lld\"\n", fp);
1722     fputs ("#define _uword_cast (long long)\n", fp);
1723     fprintf(fp, "#else\n");
1724     fputs("#define _uword_fmt \"%ld\"\n", fp);
1725     fputs ("#define _uword_cast long\n", fp);
1726     fprintf(fp, "#endif\n\n");
1727
1728     /* Walk the top-level node-list */
1729     while (np) {
1730         if (np->type == NODE_DEFINE) {
1731             if (!(np->flags & NODE_FLAG_MANUAL_PRINT)) {
1732                 fprintf(fp, 
1733        "static inline void *vl_api_%s_t_print (vl_api_%s_t *a,",
1734                         (i8 *)np->data[0], (i8 *) np->data[0]);
1735                 fprintf(fp, "void *handle)\n{\n");
1736                 /* output the message name */
1737                 fprintf(fp, 
1738                     "    vl_print(handle, \"vl_api_%s_t:\\n\");\n",
1739                         (i8 *)np->data[0]);
1740
1741                 indent += 4;
1742                 /* Yeah, this is pedantic */
1743                 vftp = the_vft[np->type];
1744                 vftp->generate(np, PRINTFUN_PASS, fp);
1745                 fprintf(fp, "    return handle;\n");
1746                 fprintf(fp, "}\n\n");
1747                 indent -= 4;
1748             } else {
1749                 fprintf(fp, "/***** manual: vl_api_%s_t_print  *****/\n\n",
1750                         (i8 *) np->data[0]);
1751             }
1752         }
1753         np = np->peer;
1754     }
1755     fprintf(fp, "#endif /* vl_printfun */\n\n");
1756 }
1757
1758 void generate_endianfun(YYSTYPE a1, FILE *fp)
1759 {
1760     node_t *np = (node_t *)a1;
1761     node_vft_t *vftp;
1762
1763     fprintf(fp, "\n/****** Endian swap functions *****/\n\n");
1764     fprintf(fp, "#ifdef vl_endianfun\n\n");
1765     fprintf(fp, "#undef clib_net_to_host_uword\n");
1766     fprintf(fp, "#ifdef LP64\n");
1767     fprintf(fp, "#define clib_net_to_host_uword clib_net_to_host_u64\n");
1768     fprintf(fp, "#else\n");
1769     fprintf(fp, "#define clib_net_to_host_uword clib_net_to_host_u32\n");
1770     fprintf(fp, "#endif\n\n");
1771
1772     /* Walk the top-level node-list */
1773     while (np) {
1774         if (np->type == NODE_DEFINE) {
1775             if (!(np->flags & NODE_FLAG_MANUAL_ENDIAN)) {
1776                 fprintf(fp, 
1777                "static inline void vl_api_%s_t_endian (vl_api_%s_t *a)\n{\n",
1778                         (i8 *) np->data[0], (i8 *) np->data[0]);
1779                 indent += 4;
1780                 /* Yeah, this is pedantic */
1781                 vftp = the_vft[np->type];
1782                 vftp->generate(np, ENDIANFUN_PASS, fp);
1783                 fprintf(fp, "}\n\n");
1784                 indent -= 4;
1785             } else {
1786                 fprintf(fp, "/***** manual: vl_api_%s_t_endian  *****/\n\n",
1787                         (i8 *) np->data[0]);
1788             }
1789         }
1790         np = np->peer;
1791     }
1792     fprintf(fp, "#endif /* vl_endianfun */\n\n");
1793 }
1794
1795 void add_msg_ids(YYSTYPE a1)
1796 {
1797     node_t *np = (node_t *)a1;
1798     node_t *new_u16;
1799     node_t *new_vbl;
1800
1801     /* Walk the top-level node-list */
1802     while (np) {
1803         if (np->type == NODE_DEFINE) {
1804             if (!(np->flags & NODE_FLAG_TYPEONLY)) {
1805                 /* add the parse tree for "u16 _vl_msg_id" */
1806                 new_u16 = make_node(NODE_U16);
1807                 new_u16->peer = np->deeper;
1808                 np->deeper = new_u16;
1809                 new_vbl = make_node(NODE_SCALAR);
1810                 new_vbl->data[0] = sxerox("_vl_msg_id");
1811                 new_u16->deeper = new_vbl;
1812             }
1813         }
1814         np = np->peer;
1815     }
1816 }
1817
1818 void generate_java_top_boilerplate(FILE *fp)
1819
1820 {
1821     char *datestring = ctime(&starttime);
1822     fixed_name = fixup_input_filename();
1823
1824     datestring[24] = 0;
1825
1826     fprintf (fp, "/*\n");
1827     fprintf (fp, " * VLIB API java binding %s\n", datestring);
1828     fprintf (fp, " * Input file: %s\n", input_filename);
1829     fprintf (fp, " * Automatically generated: please edit the input file ");
1830     fprintf (fp, "NOT this file!\n");
1831     fprintf (fp, " */\n\n");
1832
1833     fprintf (fp, "package org.openvpp.vppjapi;\n\n");
1834     fprintf (fp, "import java.io.IOException;\n\n");
1835     fprintf (fp, "public class %s extends vppConn {\n",
1836              java_class);
1837     fprintf (fp, "    public %s(String clientName) throws IOException {\n", java_class);
1838     fprintf (fp, "        super(clientName);\n");
1839     fprintf (fp, "    }\n\n");
1840 }
1841
1842 void generate_java_bottom_boilerplate(FILE *fp)
1843 {
1844     fprintf (fp, "}\n");
1845 }
1846
1847
1848 void generate_java_class_definition (YYSTYPE a1, FILE *fp)
1849 {
1850     node_t *np = (node_t *)a1;
1851     node_vft_t *vftp;
1852
1853     fprintf(fp, "/****** API methods *****/\n\n");
1854
1855     /* Walk the top-level node-list */
1856     while (np) {
1857         if (np->type == NODE_DEFINE) {
1858             if (!(np->flags & (NODE_FLAG_MANUAL_JAVA | NODE_FLAG_TYPEONLY))) {
1859                 /* Suppress messages named "xyz_reply" */
1860                 char * cp = (char *) np->data[0];
1861                 while (*cp)
1862                     cp++;
1863                 cp -= 6;
1864                 if (strncmp (cp, "_reply", 6)) {
1865                     current_java_parameter_number = 0;
1866                     vftp = the_vft[np->type];
1867                     vftp->generate(np, JAVA_METHOD_PASS, fp);
1868                 }
1869             }
1870         }
1871         np = np->peer;
1872     }
1873
1874     fprintf(fp, "\n/****** end of API methods *****/\n");
1875 }
1876
1877 void generate_jni_reply_handler_list (YYSTYPE a1, FILE *fp)
1878 {
1879     node_t *np = (node_t *)a1;
1880     node_vft_t *vftp;
1881
1882     fprintf (fp, "#define foreach_api_reply_handler \\\n");
1883
1884     /* Walk the top-level node-list */
1885     while (np) {
1886         if (np->type == NODE_DEFINE) {
1887             if (!(np->flags & (NODE_FLAG_MANUAL_JAVA | NODE_FLAG_TYPEONLY))) {
1888                 /* emit messages named "xyz_reply" */
1889                 char * cp = (char *) np->data[0];
1890                 while (*cp)
1891                     cp++;
1892                 cp -= 6;
1893                 if (!strncmp (cp, "_reply", 6)) {
1894                     fprintf (fp, "_(%s, %s) \\\n", 
1895                              uppercase(np->data[0]), (char *)(np->data[0]));
1896                 }
1897             }
1898         }
1899         np = np->peer;
1900     }
1901
1902     fprintf (fp, "\n\n");
1903 }
1904
1905 char * m_macro_boilerplate =     
1906 "#define M(T,t)                                      \\\n"
1907 "do {                                                \\\n"
1908 "    api_result_ready = 0;                           \\\n"
1909 "    mp = vl_msg_api_alloc(sizeof(*mp));             \\\n"
1910 "    memset (mp, 0, sizeof (*mp));                   \\\n"
1911 "    mp->_vl_msg_id = ntohs (VL_API_##T);            \\\n"
1912 "    mp->client_index = api_main.my_client_index;    \\\n"
1913 "} while(0);\n\n"
1914 "#define M2(T,t,n)                                   \\\n"
1915 "do {                                                \\\n"
1916 "    api_result_ready = 0;                           \\\n"
1917 "    mp = vl_msg_api_alloc(sizeof(*mp)+(n));         \\\n"
1918 "    memset (mp, 0, sizeof (*mp));                   \\\n"
1919 "    mp->_vl_msg_id = ntohs (VL_API_##T);            \\\n"
1920 "    mp->client_index = api_main.my_client_index;    \\\n"
1921 "} while(0);\n\n";
1922
1923 char * s_macro_boilerplate = 
1924 "#define S (vl_msg_api_send_shmem (api_main.shmem_hdr->vl_input_queue, \\\n"
1925 "(u8 *)&mp));\n\n";
1926
1927 char * w_macro_boilerplate = 
1928 "#define W                                               \\\n"
1929 "do {                                                    \\\n"
1930 "    timeout = clib_time_now (&clib_time) + 1.0;         \\\n"
1931 "                                                        \\\n"
1932 "    while (clib_time_now (&clib_time) < timeout) {      \\\n"
1933 "        if (api_result_ready == 1) {                    \\\n"
1934 "            return ((jint) api_result);                 \\\n"    
1935 "        }                                               \\\n"
1936 "    }                                                   \\\n"
1937 "    return -99;                                         \\\n"   
1938 "} while(0);\n\n";
1939
1940 void generate_jni_top_boilerplate(FILE *fp)
1941
1942 {
1943     char *datestring = ctime(&starttime);
1944     fixed_name = fixup_input_filename();
1945
1946     datestring[24] = 0;
1947
1948     fprintf (fp, "/*\n");
1949     fprintf (fp, " * VLIB Java native code %s\n", datestring);
1950     fprintf (fp, " * Input file: %s\n", input_filename);
1951     fprintf (fp, " * Automatically generated: please edit the input file ");
1952     fprintf (fp, "NOT this file!\n");
1953     fprintf (fp, " */\n\n");
1954
1955     fprintf (fp, "#include <japi/vppjni.h>\n");
1956
1957     fprintf (fp, 
1958              "#define vl_api_version(n,v) static u32 %s_api_version %s = v;\n",
1959              vlib_app_name, "__attribute__((unused))");
1960     fprintf (fp, "#include <api/%s.api.h>\n", vlib_app_name);
1961     fprintf (fp, "#undef vl_api_version\n\n");
1962
1963     fprintf (fp, "#include <japi/org_openvpp_vppjapi_vppConn.h>\n");
1964     fprintf (fp, "#include <japi/org_openvpp_vppjapi_%s.h>\n\n", java_class);
1965
1966     fprintf (fp, "#include <api/%s_msg_enum.h>\n", vlib_app_name);
1967     fprintf (fp, "#define vl_typedefs /* define message structures */\n");
1968     fprintf (fp, "#include <api/%s_all_api_h.h> \n", vlib_app_name);
1969     fprintf (fp, "#undef vl_typedefs\n\n");
1970
1971     fprintf (fp, "#define vl_endianfun \n");
1972     fprintf (fp, "#include <api/%s_all_api_h.h> \n", vlib_app_name);
1973     fprintf (fp, "#undef vl_endianfun\n\n");
1974
1975     fprintf (fp, "#define vl_print(handle, ...)\n");
1976     fprintf (fp, "#define vl_printfun\n");
1977     fprintf (fp, "#include <api/%s_all_api_h.h>\n", vlib_app_name);
1978     fprintf (fp, "#undef vl_printfun\n\n");
1979 }
1980
1981 void generate_jni_code (YYSTYPE a1, FILE *fp)
1982 {
1983     node_t *np = (node_t *)a1;
1984     node_vft_t *vftp;
1985
1986     /* Walk the top-level node-list */
1987     while (np) {
1988         if (np->type == NODE_DEFINE) {
1989             if (!(np->flags & (NODE_FLAG_MANUAL_JAVA | NODE_FLAG_TYPEONLY))) {
1990                 /* Suppress messages named "xyz_reply" */
1991                 char * cp = (char *) np->data[0];
1992                 while (*cp)
1993                     cp++;
1994                 cp -= 6;
1995                 if (strncmp (cp, "_reply", 6)) {
1996                     current_def_name = np->data[0];
1997                     current_java_parameter_number = 0;
1998                     vftp = the_vft[np->type];
1999                     vftp->generate(np, JAVA_JNI_PASS, fp);
2000                 }
2001             }
2002         }
2003         np = np->peer;
2004     }
2005 }
2006
2007 char *hookup_boilerplate = 
2008 "void vl_msg_reply_handler_hookup (void)\n"
2009 "{\n"
2010 "#define _(N,n) \\\n"
2011 "    vl_msg_api_set_handlers (VL_API_##N, #n, \\\n"
2012 "        vl_api_generic_reply_handler, \\\n"
2013 "        vl_noop_handler, \\\n"
2014 "        vl_api_##n##_t_endian, \\\n"
2015 "        vl_api_##n##_t_print, \\\n"
2016 "        sizeof(vl_api_##n##_t), 1); \n"
2017 "    foreach_api_reply_handler;\n"
2018 "#undef _\n\n"
2019 "}\n\n";
2020     
2021 void generate_jni_bottom_boilerplate(FILE *fp)
2022 {
2023     fputs (hookup_boilerplate, fp);
2024 }
2025
2026 void generate_python (YYSTYPE a1, FILE *fp)
2027 {
2028   node_t *np = (node_t *)a1;
2029   node_vft_t *vftp;
2030   fprintf (fp, "vppapidef = [\n");
2031   /* Walk the top-level node-list */
2032   while (np) {
2033     if (np->type == NODE_DEFINE && !(np->flags & NODE_FLAG_TYPEONLY)) {
2034       /* Yeah, this is pedantic */
2035       vftp = the_vft[np->type];
2036       vftp->generate(np, PYTHON_PASS, fp);
2037     }
2038     np = np->peer;
2039   }
2040   fprintf (fp, "\n]\n");
2041 }
2042
2043 void generate(YYSTYPE a1)
2044 {
2045     if (dump_tree) {
2046         dump((node_t *)a1);
2047     }
2048
2049     add_msg_ids(a1);
2050
2051     if (ofp) {
2052         generate_top_boilerplate(ofp);
2053
2054         generate_msg_ids(a1, ofp);
2055         generate_msg_names(a1, ofp);
2056         generate_typedefs(a1, ofp);
2057         generate_uniondefs(a1, ofp);
2058         generate_printfun(a1, ofp);
2059         generate_endianfun(a1, ofp);
2060         
2061         generate_bottom_boilerplate(ofp);
2062     }
2063
2064     if (javafp) {
2065         generate_java_top_boilerplate(javafp);
2066         generate_java_class_definition(a1, javafp);
2067         generate_java_bottom_boilerplate(javafp);
2068     }
2069     if (jnifp) {
2070         generate_jni_top_boilerplate(jnifp);
2071         generate_jni_reply_handler_list (a1, jnifp);
2072         generate_jni_code(a1, jnifp);
2073         generate_jni_bottom_boilerplate(jnifp);
2074     }
2075     if (pythonfp) {
2076       generate_python(a1, pythonfp);
2077     }
2078 }