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