449540c3858f8d3c7fd6e26cb40f96184da8ba49
[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 < %lu; _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         if (CDATA2 != 0) { // variable length vector
1165             fprintf(fp, "'%s', '%d', '%s'),\n", CDATA0, IDATA1, CDATA2);
1166         } else {
1167             fprintf(fp, "'%s', '%d'),\n", CDATA0, IDATA1);
1168         }
1169         break;
1170
1171     default:
1172         fprintf(stderr, "node_vector_generate: unimp pass %d\n", which);
1173     }
1174     if (this->deeper) {
1175         fprintf(stderr, "broken recursion in node_vector_generate\n");
1176     }
1177 }
1178
1179 node_vft_t node_vector_vft = {
1180     node_vector_print,
1181     node_vector_generate,
1182     0,
1183 };
1184
1185 void node_complex_print (node_t *this)
1186 {
1187     primtype_recursive_print (this, "complex ");
1188 }
1189
1190 void node_complex_generate (node_t *this, enum passid which, FILE *fp)
1191 {
1192     node_t *deeper;
1193     node_vft_t *vftp;
1194     char *member_name = "broken!";
1195     char *union_prefix = "";
1196
1197     if (current_union_name) {
1198         sprintf(tmpbuf, "%s.", current_union_name);
1199         union_prefix = tmpbuf;
1200     }
1201
1202     current_is_complex++;
1203     
1204     switch(which) {
1205     case TYPEDEF_PASS:
1206         fprintf(fp, "%s ", CDATA0);
1207         deeper = this->deeper;
1208         if (deeper) {
1209             vftp = the_vft[deeper->type];
1210             vftp->generate(deeper, which, fp);
1211         }
1212         break;
1213
1214     case PRINTFUN_PASS:
1215         deeper = this->deeper;
1216         while (deeper) {
1217             if (deeper->type == NODE_SCALAR ||
1218                 deeper->type == NODE_VECTOR) {
1219                 member_name = deeper->data[0];
1220                 break;
1221             }
1222             deeper = deeper->deeper;
1223         }
1224         indent_me(fp);
1225         fprintf(fp, "vl_print(handle, \"%s%s ----- \\n\");\n", 
1226                 union_prefix, member_name);
1227         indent_me(fp);
1228         fprintf(fp, "%s_print(&a->%s%s, handle);\n", 
1229                 CDATA0, union_prefix, member_name);
1230         indent_me(fp);
1231         fprintf(fp, "vl_print(handle, \"%s%s ----- END \\n\");\n", 
1232                 union_prefix, member_name);
1233         break;
1234
1235     case ENDIANFUN_PASS:
1236         deeper = this->deeper;
1237         while (deeper) {
1238             if (deeper->type == NODE_SCALAR ||
1239                 deeper->type == NODE_VECTOR) {
1240                 member_name = deeper->data[0];
1241                 break;
1242             }
1243             deeper = deeper->deeper;
1244         }
1245
1246         indent_me(fp);
1247         fprintf(fp, "%s_endian(&a->%s%s);\n", 
1248                 CDATA0, union_prefix, member_name);
1249         break;
1250     case PYTHON_PASS:
1251         fprintf(fp, "('%s',", CDATA0);
1252         deeper = this->deeper;
1253         if (deeper) {
1254             vftp = the_vft[deeper->type];
1255             vftp->generate(deeper, which, fp);
1256         }
1257         break;
1258
1259     default:
1260         fprintf(stderr, "node_complex_generate unimp pass %d...\n", which);
1261         break;
1262     }
1263     current_is_complex--;
1264 }
1265
1266 node_vft_t node_complex_vft = {
1267     node_complex_print,
1268     node_complex_generate,
1269     0,
1270 };
1271
1272 void node_noversion_print (node_t *this)
1273 {
1274     primtype_recursive_print (this, "noversion ");
1275 }
1276
1277 void node_noversion_generate (node_t *this, enum passid which, FILE *ofp)
1278 {
1279     fprintf(stderr, "node_noversion_generate called...\n");
1280 }
1281
1282 node_vft_t node_noversion_vft = {
1283     node_noversion_print,
1284     node_noversion_generate,
1285     0,
1286 };
1287
1288 void node_uword_print (node_t *this)
1289 {
1290     primtype_recursive_print(this, "uword ");
1291 }
1292
1293 void node_uword_generate (node_t *this, enum passid which, FILE *ofp)
1294 {
1295     primtype_recursive_generate(this, which, ofp, "uword", "uword", "");
1296 }
1297
1298 node_vft_t node_uword_vft = {
1299     node_uword_print,
1300     node_uword_generate,
1301     "clib_net_to_host_uword",
1302 };
1303
1304 node_vft_t *the_vft[NODE_N_TYPES] = {
1305     &node_illegal_vft,
1306     &node_u8_vft,
1307     &node_u16_vft,
1308     &node_u32_vft,
1309     &node_u64_vft,
1310     &node_i8_vft,
1311     &node_i16_vft,
1312     &node_i32_vft,
1313     &node_i64_vft,
1314     &node_f64_vft,
1315     &node_packed_vft,
1316     &node_define_vft,
1317     &node_union_vft,
1318     &node_scalar_vft,
1319     &node_vector_vft,
1320     &node_complex_vft,
1321     &node_noversion_vft,
1322     &node_uword_vft,
1323 };
1324
1325 void *make_node (enum node_subclass type)
1326 {
1327     node_t *rv;
1328
1329     rv = (node_t *) malloc (sizeof (*rv));
1330     if (rv == 0) {
1331         fprintf (stderr, "fatal: make_node out of memory\n");
1332         exit (1);
1333     }
1334     bzero (rv, sizeof (*rv));
1335     rv->type = type;
1336     return ((void *) rv);
1337 }
1338
1339 YYSTYPE deeper (YYSTYPE arg1, YYSTYPE arg2)
1340 {
1341     node_t *np1 = (node_t *) arg1;
1342     node_t *np2 = (node_t *) arg2;
1343     node_t *hook_point;
1344     
1345     hook_point = np1;
1346
1347     while (hook_point->deeper)
1348         hook_point = hook_point->deeper;
1349
1350     hook_point->deeper = np2;
1351     return (arg1);
1352 }
1353
1354 YYSTYPE addpeer (YYSTYPE arg1, YYSTYPE arg2)
1355 {
1356     node_t *np1 = (node_t *) arg1;
1357     node_t *np2 = (node_t *) arg2;
1358     node_t *hook_point;
1359     
1360     hook_point = np1;
1361
1362     while (hook_point->peer)
1363         hook_point = hook_point->peer;
1364
1365     hook_point->peer = np2;
1366     return (arg1);
1367 }
1368
1369 /*
1370  * add_slist (stmt_list, stmt)
1371  */
1372
1373 YYSTYPE add_slist (YYSTYPE a1, YYSTYPE a2)
1374 {
1375     if (a1 && a2)
1376         return (addpeer(a1, a2));
1377     else if(a1)
1378         return(a1);
1379     else 
1380         return(a2);
1381 }
1382
1383 /*
1384  * add_define (char *name, defn_list);
1385  */
1386 YYSTYPE add_define (YYSTYPE a1, YYSTYPE a2)
1387 {
1388     node_t *np;
1389
1390     np = make_node(NODE_DEFINE);
1391     np->data[0] = a1;
1392     deeper((YYSTYPE)np, a2);
1393     return ((YYSTYPE) np);
1394 }
1395
1396 /*
1397  * add_defbody (defn_list, new_defn)
1398  */
1399 YYSTYPE add_defbody (YYSTYPE a1, YYSTYPE a2)
1400 {
1401     return (addpeer(a1, a2));
1402 }
1403
1404 /*
1405  * add_primtype ([packed], primitive type, instance)
1406  */ 
1407
1408 YYSTYPE add_primtype (YYSTYPE a1, YYSTYPE a2, YYSTYPE a3)
1409 {
1410     node_t *np1;
1411
1412     np1 = (node_t *)a1;
1413     
1414     /* Hook instance to type node */
1415     deeper (a1, a2);
1416     if (a3) {
1417         deeper(a1, a3);
1418     }
1419     return (a1);
1420 }
1421
1422 /*
1423  * add_complex(char *type_name, instance)
1424  */
1425
1426 YYSTYPE add_complex (YYSTYPE a1, YYSTYPE a2)
1427 {
1428     node_t *np;
1429
1430     np = make_node(NODE_COMPLEX);
1431     np->data[0] = (void *) a1;
1432
1433     deeper((YYSTYPE)np, a2);
1434     return ((YYSTYPE) np);
1435 }
1436
1437 /*
1438  * add_union(char *type_name, definition)
1439  */
1440
1441 YYSTYPE add_union (YYSTYPE a1, YYSTYPE a2)
1442 {
1443     node_t *np;
1444
1445     np = make_node(NODE_UNION);
1446     np->data[0] = (void *) a1;
1447
1448     deeper((YYSTYPE)np, a2);
1449     return ((YYSTYPE) np);
1450 }
1451
1452
1453 /*
1454  * add_vector_vbl (node_t *variable, YYSTYPE size)
1455  */
1456
1457 YYSTYPE add_vector_vbl (YYSTYPE a1, YYSTYPE a2)
1458 {
1459     node_t *np;
1460
1461     np = make_node(NODE_VECTOR);
1462     np->data[0] = (void *) a1;
1463     np->data[1] = (void *) a2;
1464     return ((YYSTYPE) np);
1465 }
1466
1467 /*
1468  * add_vector_vbl (char *vector_name, char *vector_length_var)
1469  */
1470
1471 YYSTYPE add_variable_length_vector_vbl (YYSTYPE vector_name, YYSTYPE vector_length_var)
1472 {
1473     node_t *np;
1474
1475     np = make_node(NODE_VECTOR);
1476     np->data[0] = (void *) vector_name;
1477     np->data[1] = (void *) 0; // vector size used for vpe.api.h generation (array of length zero)
1478     np->data[2] = (void *) vector_length_var; // name of the variable that stores vector length
1479     return ((YYSTYPE) np);
1480 }
1481
1482 /*
1483  * add_scalar_vbl (char *name)
1484  */
1485 YYSTYPE add_scalar_vbl (YYSTYPE a1)
1486 {
1487     node_t *np;
1488
1489     np = make_node(NODE_SCALAR);
1490     np->data[0] = (void *) a1;
1491     return ((YYSTYPE) np);
1492 }
1493
1494 /*
1495  * set_flags (int flags, msg(=0?))
1496  */ 
1497 YYSTYPE set_flags(YYSTYPE a1, YYSTYPE a2)
1498 {
1499     node_t *np;
1500     int flags;
1501
1502     np = (node_t *)a2;
1503     if (!np)
1504         return(0);
1505
1506     flags = (int)(uword) a1;
1507
1508     np->flags |= flags;
1509     return (a2);
1510 }
1511 /*
1512  * suppress_version
1513  */
1514 YYSTYPE suppress_version (void)
1515 {
1516     dont_output_version = 1;
1517     return (0);
1518 }
1519
1520 void dump(node_t *np)
1521 {
1522     node_vft_t *vftp;
1523
1524     while (np) {
1525         vftp = the_vft[np->type];
1526         vftp->print(np);
1527         np = np->peer;
1528     }
1529 }
1530
1531 char *fixup_input_filename(void)
1532 {
1533     char *cp;
1534
1535     cp = (char *)input_filename;
1536
1537     while (*cp)
1538         cp++;
1539
1540     cp--;
1541
1542     while (cp > input_filename && *cp != '/')
1543         cp--;
1544     if (*cp == '/')
1545         cp++;
1546
1547     strcpy (tmpbuf, cp);
1548
1549     cp = tmpbuf;
1550
1551     while (*cp)
1552         cp++;
1553
1554     cp--;
1555
1556     while (cp > tmpbuf && *cp != '.')
1557         cp--;
1558     
1559     if (*cp == '.')
1560         *cp = 0;
1561
1562     return (sxerox(tmpbuf));
1563 }
1564
1565 void generate_top_boilerplate(FILE *fp)
1566
1567 {
1568     char *datestring = ctime(&starttime);
1569     fixed_name = fixup_input_filename();
1570
1571     datestring[24] = 0;
1572
1573     fprintf (fp, "/*\n");
1574     fprintf (fp, " * VLIB API definitions %s\n", datestring);
1575     fprintf (fp, " * Input file: %s\n", input_filename);
1576     fprintf (fp, " * Automatically generated: please edit the input file ");
1577     fprintf (fp, "NOT this file!\n");
1578
1579     /* Moron Acme trigger workaround */
1580     fprintf (fp, " * %syright (c) %s by Cisco Systems, Inc.\n", "Cop", 
1581              &datestring[20]);
1582     fprintf (fp, " */\n\n");
1583     fprintf (fp, "#if defined(vl_msg_id)||defined(vl_union_id)||");
1584     fprintf (fp, "defined(vl_printfun) \\\n ||defined(vl_endianfun)||");
1585     fprintf (fp, " defined(vl_api_version)||defined(vl_typedefs) \\\n");
1586     fprintf (fp, " ||defined(vl_msg_name)\n");
1587     fprintf (fp, "/* ok, something was selected */\n");
1588     fprintf (fp, "#else\n");
1589     fprintf (fp, "#warning no content included from %s\n", input_filename);
1590     fprintf (fp, "#endif\n\n");
1591     fprintf (fp, "#define VL_API_PACKED(x) x __attribute__ ((packed))\n\n");
1592 }
1593
1594 void generate_bottom_boilerplate(FILE *fp)
1595
1596 {
1597     fprintf (fp, "\n#ifdef vl_api_version\n");
1598
1599     if (dont_output_version) {
1600         fprintf (fp, "/* WARNING: API FILE VERSION CHECK DISABLED */\n");
1601         input_crc = 0;
1602     }
1603
1604     fprintf (fp, "vl_api_version(%s, 0x%08x)\n\n", 
1605              fixed_name, (unsigned int)input_crc);
1606     fprintf (fp, "#endif\n\n");
1607 }
1608
1609 void generate_msg_ids(YYSTYPE a1, FILE *fp)
1610 {
1611     node_t *np = (node_t *)a1;
1612
1613     fprintf (fp, "\n/****** Message ID / handler enum ******/\n\n");
1614     fprintf (fp, "#ifdef vl_msg_id\n");
1615
1616     while (np) {
1617         if (np->type == NODE_DEFINE) {
1618             if (!(np->flags & NODE_FLAG_TYPEONLY)) {
1619                 fprintf (fp, "vl_msg_id(VL_API_%s, vl_api_%s_t_handler)\n", 
1620                          uppercase(np->data[0]), (i8 *)np->data[0]);
1621             } else {
1622                 fprintf (fp, "/* typeonly: %s */\n", (i8 *)np->data[0]);
1623             }
1624         }
1625         np = np->peer;
1626     }
1627     fprintf (fp, "#endif\n");
1628
1629 }
1630
1631 void generate_msg_names(YYSTYPE a1, FILE *fp)
1632 {
1633     node_t *np = (node_t *)a1;
1634
1635     fprintf (fp, "\n/****** Message names ******/\n\n");
1636
1637     fprintf (fp, "#ifdef vl_msg_name\n");
1638
1639     while (np) {
1640         if (np->type == NODE_DEFINE) {
1641             if (!(np->flags & NODE_FLAG_TYPEONLY)) {
1642                 fprintf (fp, "vl_msg_name(vl_api_%s_t, %d)\n",
1643                          (i8 *) np->data[0], 
1644                          (np->flags & NODE_FLAG_DONT_TRACE ? 0 : 1));
1645             } else {
1646                 fprintf (fp, "/* typeonly: %s */\n", (i8 *)np->data[0]);
1647             }
1648         }
1649         np = np->peer;
1650     }
1651     fprintf (fp, "#endif\n\n");
1652 }
1653
1654 void generate_typedefs(YYSTYPE a1, FILE *fp)
1655 {
1656     node_t *np = (node_t *)a1;
1657     node_vft_t *vftp;
1658
1659     fprintf(fp, "\n/****** Typedefs *****/\n\n");
1660     fprintf(fp, "#ifdef vl_typedefs\n\n");
1661
1662     /* Walk the top-level node-list */
1663     while (np) {
1664         if (np->type == NODE_DEFINE) {
1665             /* Yeah, this is pedantic */
1666             vftp = the_vft[np->type];
1667             vftp->generate(np, TYPEDEF_PASS, fp);
1668         }
1669         np = np->peer;
1670     }
1671     fprintf(fp, "#endif /* vl_typedefs */\n\n");
1672 }
1673
1674 void union_walk_one_defn(node_t *np, FILE *fp)
1675 {
1676     node_t *vblp;
1677     node_t *uelem;
1678
1679     /* Walk the list of typed objects in this msg def */
1680     while (np) {
1681         if (np->type == NODE_UNION) {
1682             current_union_name = np->data[0];
1683             uelem = np->deeper;
1684
1685             /* Walk the list of objects in this union */
1686             while (uelem) {
1687                 vblp = uelem->deeper;
1688                 /* Drill down on each element, find the variable name */
1689                 while(vblp) {
1690                     if (vblp->type == NODE_SCALAR ||
1691                         vblp->type == NODE_VECTOR ||
1692                         vblp->type == NODE_COMPLEX) {
1693                         fprintf(ofp, "#define %s_", 
1694                                 uppercase(current_def_name));
1695                         fprintf(ofp, "%s_", uppercase(current_union_name));
1696                         fprintf(ofp, "%s %d\n",uppercase(vblp->data[0]),
1697                                 current_id);
1698                         current_id++;
1699                         break;
1700                     }
1701                     vblp = vblp->deeper;
1702                 }
1703                 uelem = uelem->peer;
1704             }
1705             current_union_name = 0;
1706             current_id = 1;
1707         }
1708         np = np->peer;
1709     }
1710 }
1711
1712 void generate_uniondefs(YYSTYPE a1, FILE *fp)
1713 {
1714     node_t *np = (node_t *)a1;
1715
1716     fprintf(fp, "/****** Discriminated Union Definitions *****/\n\n");
1717     fprintf(fp, "#ifdef vl_union_id\n\n");
1718
1719     /* Walk the top-level node-list */
1720     while (np) {
1721         if (np->type == NODE_DEFINE) {
1722             current_id = 1;
1723             current_def_name = np->data[0];
1724             union_walk_one_defn(np->deeper, fp);
1725         }
1726         np = np->peer;
1727     }
1728     fprintf(fp, "\n#endif /* vl_union_id */\n\n");
1729 }
1730
1731 void generate_printfun(YYSTYPE a1, FILE *fp)
1732 {
1733     node_t *np = (node_t *)a1;
1734     node_vft_t *vftp;
1735
1736     fprintf(fp, "/****** Print functions *****/\n\n");
1737     fprintf(fp, "#ifdef vl_printfun\n\n");
1738
1739     fprintf(fp, "#ifdef LP64\n");
1740     fputs ("#define _uword_fmt \"%lld\"\n", fp);
1741     fputs ("#define _uword_cast (long long)\n", fp);
1742     fprintf(fp, "#else\n");
1743     fputs("#define _uword_fmt \"%ld\"\n", fp);
1744     fputs ("#define _uword_cast long\n", fp);
1745     fprintf(fp, "#endif\n\n");
1746
1747     /* Walk the top-level node-list */
1748     while (np) {
1749         if (np->type == NODE_DEFINE) {
1750             if (!(np->flags & NODE_FLAG_MANUAL_PRINT)) {
1751                 fprintf(fp, 
1752        "static inline void *vl_api_%s_t_print (vl_api_%s_t *a,",
1753                         (i8 *)np->data[0], (i8 *) np->data[0]);
1754                 fprintf(fp, "void *handle)\n{\n");
1755                 /* output the message name */
1756                 fprintf(fp, 
1757                     "    vl_print(handle, \"vl_api_%s_t:\\n\");\n",
1758                         (i8 *)np->data[0]);
1759
1760                 indent += 4;
1761                 /* Yeah, this is pedantic */
1762                 vftp = the_vft[np->type];
1763                 vftp->generate(np, PRINTFUN_PASS, fp);
1764                 fprintf(fp, "    return handle;\n");
1765                 fprintf(fp, "}\n\n");
1766                 indent -= 4;
1767             } else {
1768                 fprintf(fp, "/***** manual: vl_api_%s_t_print  *****/\n\n",
1769                         (i8 *) np->data[0]);
1770             }
1771         }
1772         np = np->peer;
1773     }
1774     fprintf(fp, "#endif /* vl_printfun */\n\n");
1775 }
1776
1777 void generate_endianfun(YYSTYPE a1, FILE *fp)
1778 {
1779     node_t *np = (node_t *)a1;
1780     node_vft_t *vftp;
1781
1782     fprintf(fp, "\n/****** Endian swap functions *****/\n\n");
1783     fprintf(fp, "#ifdef vl_endianfun\n\n");
1784     fprintf(fp, "#undef clib_net_to_host_uword\n");
1785     fprintf(fp, "#ifdef LP64\n");
1786     fprintf(fp, "#define clib_net_to_host_uword clib_net_to_host_u64\n");
1787     fprintf(fp, "#else\n");
1788     fprintf(fp, "#define clib_net_to_host_uword clib_net_to_host_u32\n");
1789     fprintf(fp, "#endif\n\n");
1790
1791     /* Walk the top-level node-list */
1792     while (np) {
1793         if (np->type == NODE_DEFINE) {
1794             if (!(np->flags & NODE_FLAG_MANUAL_ENDIAN)) {
1795                 fprintf(fp, 
1796                "static inline void vl_api_%s_t_endian (vl_api_%s_t *a)\n{\n",
1797                         (i8 *) np->data[0], (i8 *) np->data[0]);
1798                 indent += 4;
1799                 /* Yeah, this is pedantic */
1800                 vftp = the_vft[np->type];
1801                 vftp->generate(np, ENDIANFUN_PASS, fp);
1802                 fprintf(fp, "}\n\n");
1803                 indent -= 4;
1804             } else {
1805                 fprintf(fp, "/***** manual: vl_api_%s_t_endian  *****/\n\n",
1806                         (i8 *) np->data[0]);
1807             }
1808         }
1809         np = np->peer;
1810     }
1811     fprintf(fp, "#endif /* vl_endianfun */\n\n");
1812 }
1813
1814 void add_msg_ids(YYSTYPE a1)
1815 {
1816     node_t *np = (node_t *)a1;
1817     node_t *new_u16;
1818     node_t *new_vbl;
1819
1820     /* Walk the top-level node-list */
1821     while (np) {
1822         if (np->type == NODE_DEFINE) {
1823             if (!(np->flags & NODE_FLAG_TYPEONLY)) {
1824                 /* add the parse tree for "u16 _vl_msg_id" */
1825                 new_u16 = make_node(NODE_U16);
1826                 new_u16->peer = np->deeper;
1827                 np->deeper = new_u16;
1828                 new_vbl = make_node(NODE_SCALAR);
1829                 new_vbl->data[0] = sxerox("_vl_msg_id");
1830                 new_u16->deeper = new_vbl;
1831             }
1832         }
1833         np = np->peer;
1834     }
1835 }
1836
1837 void generate_java_top_boilerplate(FILE *fp)
1838
1839 {
1840     char *datestring = ctime(&starttime);
1841     fixed_name = fixup_input_filename();
1842
1843     datestring[24] = 0;
1844
1845     fprintf (fp, "/*\n");
1846     fprintf (fp, " * VLIB API java binding %s\n", datestring);
1847     fprintf (fp, " * Input file: %s\n", input_filename);
1848     fprintf (fp, " * Automatically generated: please edit the input file ");
1849     fprintf (fp, "NOT this file!\n");
1850     fprintf (fp, " */\n\n");
1851
1852     fprintf (fp, "package org.openvpp.vppjapi;\n\n");
1853     fprintf (fp, "import java.io.IOException;\n\n");
1854     fprintf (fp, "public class %s extends vppConn {\n",
1855              java_class);
1856     fprintf (fp, "    public %s(String clientName) throws IOException {\n", java_class);
1857     fprintf (fp, "        super(clientName);\n");
1858     fprintf (fp, "    }\n\n");
1859 }
1860
1861 void generate_java_bottom_boilerplate(FILE *fp)
1862 {
1863     fprintf (fp, "}\n");
1864 }
1865
1866
1867 void generate_java_class_definition (YYSTYPE a1, FILE *fp)
1868 {
1869     node_t *np = (node_t *)a1;
1870     node_vft_t *vftp;
1871
1872     fprintf(fp, "/****** API methods *****/\n\n");
1873
1874     /* Walk the top-level node-list */
1875     while (np) {
1876         if (np->type == NODE_DEFINE) {
1877             if (!(np->flags & (NODE_FLAG_MANUAL_JAVA | NODE_FLAG_TYPEONLY))) {
1878                 /* Suppress messages named "xyz_reply" */
1879                 char * cp = (char *) np->data[0];
1880                 while (*cp)
1881                     cp++;
1882                 cp -= 6;
1883                 if (strncmp (cp, "_reply", 6)) {
1884                     current_java_parameter_number = 0;
1885                     vftp = the_vft[np->type];
1886                     vftp->generate(np, JAVA_METHOD_PASS, fp);
1887                 }
1888             }
1889         }
1890         np = np->peer;
1891     }
1892
1893     fprintf(fp, "\n/****** end of API methods *****/\n");
1894 }
1895
1896 void generate_jni_reply_handler_list (YYSTYPE a1, FILE *fp)
1897 {
1898     node_t *np = (node_t *)a1;
1899     node_vft_t *vftp;
1900
1901     fprintf (fp, "#define foreach_api_reply_handler \\\n");
1902
1903     /* Walk the top-level node-list */
1904     while (np) {
1905         if (np->type == NODE_DEFINE) {
1906             if (!(np->flags & (NODE_FLAG_MANUAL_JAVA | NODE_FLAG_TYPEONLY))) {
1907                 /* emit messages named "xyz_reply" */
1908                 char * cp = (char *) np->data[0];
1909                 while (*cp)
1910                     cp++;
1911                 cp -= 6;
1912                 if (!strncmp (cp, "_reply", 6)) {
1913                     fprintf (fp, "_(%s, %s) \\\n", 
1914                              uppercase(np->data[0]), (char *)(np->data[0]));
1915                 }
1916             }
1917         }
1918         np = np->peer;
1919     }
1920
1921     fprintf (fp, "\n\n");
1922 }
1923
1924 char * m_macro_boilerplate =     
1925 "#define M(T,t)                                      \\\n"
1926 "do {                                                \\\n"
1927 "    api_result_ready = 0;                           \\\n"
1928 "    mp = vl_msg_api_alloc(sizeof(*mp));             \\\n"
1929 "    memset (mp, 0, sizeof (*mp));                   \\\n"
1930 "    mp->_vl_msg_id = ntohs (VL_API_##T);            \\\n"
1931 "    mp->client_index = api_main.my_client_index;    \\\n"
1932 "} while(0);\n\n"
1933 "#define M2(T,t,n)                                   \\\n"
1934 "do {                                                \\\n"
1935 "    api_result_ready = 0;                           \\\n"
1936 "    mp = vl_msg_api_alloc(sizeof(*mp)+(n));         \\\n"
1937 "    memset (mp, 0, sizeof (*mp));                   \\\n"
1938 "    mp->_vl_msg_id = ntohs (VL_API_##T);            \\\n"
1939 "    mp->client_index = api_main.my_client_index;    \\\n"
1940 "} while(0);\n\n";
1941
1942 char * s_macro_boilerplate = 
1943 "#define S (vl_msg_api_send_shmem (api_main.shmem_hdr->vl_input_queue, \\\n"
1944 "(u8 *)&mp));\n\n";
1945
1946 char * w_macro_boilerplate = 
1947 "#define W                                               \\\n"
1948 "do {                                                    \\\n"
1949 "    timeout = clib_time_now (&clib_time) + 1.0;         \\\n"
1950 "                                                        \\\n"
1951 "    while (clib_time_now (&clib_time) < timeout) {      \\\n"
1952 "        if (api_result_ready == 1) {                    \\\n"
1953 "            return ((jint) api_result);                 \\\n"    
1954 "        }                                               \\\n"
1955 "    }                                                   \\\n"
1956 "    return -99;                                         \\\n"   
1957 "} while(0);\n\n";
1958
1959 void generate_jni_top_boilerplate(FILE *fp)
1960
1961 {
1962     char *datestring = ctime(&starttime);
1963     fixed_name = fixup_input_filename();
1964
1965     datestring[24] = 0;
1966
1967     fprintf (fp, "/*\n");
1968     fprintf (fp, " * VLIB Java native code %s\n", datestring);
1969     fprintf (fp, " * Input file: %s\n", input_filename);
1970     fprintf (fp, " * Automatically generated: please edit the input file ");
1971     fprintf (fp, "NOT this file!\n");
1972     fprintf (fp, " */\n\n");
1973
1974     fprintf (fp, "#include <japi/vppjni.h>\n");
1975
1976     fprintf (fp, 
1977              "#define vl_api_version(n,v) static u32 %s_api_version %s = v;\n",
1978              vlib_app_name, "__attribute__((unused))");
1979     fprintf (fp, "#include <vpp-api/%s.api.h>\n", vlib_app_name);
1980     fprintf (fp, "#undef vl_api_version\n\n");
1981
1982     fprintf (fp, "#include <japi/org_openvpp_vppjapi_vppConn.h>\n");
1983     fprintf (fp, "#include <japi/org_openvpp_vppjapi_%s.h>\n\n", java_class);
1984
1985     fprintf (fp, "#include <vpp-api/%s_msg_enum.h>\n", vlib_app_name);
1986     fprintf (fp, "#define vl_typedefs /* define message structures */\n");
1987     fprintf (fp, "#include <vpp-api/%s_all_api_h.h> \n", vlib_app_name);
1988     fprintf (fp, "#undef vl_typedefs\n\n");
1989
1990     fprintf (fp, "#define vl_endianfun \n");
1991     fprintf (fp, "#include <vpp-api/%s_all_api_h.h> \n", vlib_app_name);
1992     fprintf (fp, "#undef vl_endianfun\n\n");
1993
1994     fprintf (fp, "#define vl_print(handle, ...)\n");
1995     fprintf (fp, "#define vl_printfun\n");
1996     fprintf (fp, "#include <vpp-api/%s_all_api_h.h>\n", vlib_app_name);
1997     fprintf (fp, "#undef vl_printfun\n\n");
1998 }
1999
2000 void generate_jni_code (YYSTYPE a1, FILE *fp)
2001 {
2002     node_t *np = (node_t *)a1;
2003     node_vft_t *vftp;
2004
2005     /* Walk the top-level node-list */
2006     while (np) {
2007         if (np->type == NODE_DEFINE) {
2008             if (!(np->flags & (NODE_FLAG_MANUAL_JAVA | NODE_FLAG_TYPEONLY))) {
2009                 /* Suppress messages named "xyz_reply" */
2010                 char * cp = (char *) np->data[0];
2011                 while (*cp)
2012                     cp++;
2013                 cp -= 6;
2014                 if (strncmp (cp, "_reply", 6)) {
2015                     current_def_name = np->data[0];
2016                     current_java_parameter_number = 0;
2017                     vftp = the_vft[np->type];
2018                     vftp->generate(np, JAVA_JNI_PASS, fp);
2019                 }
2020             }
2021         }
2022         np = np->peer;
2023     }
2024 }
2025
2026 char *hookup_boilerplate = 
2027 "void vl_msg_reply_handler_hookup (void)\n"
2028 "{\n"
2029 "#define _(N,n) \\\n"
2030 "    vl_msg_api_set_handlers (VL_API_##N, #n, \\\n"
2031 "        vl_api_generic_reply_handler, \\\n"
2032 "        vl_noop_handler, \\\n"
2033 "        vl_api_##n##_t_endian, \\\n"
2034 "        vl_api_##n##_t_print, \\\n"
2035 "        sizeof(vl_api_##n##_t), 1); \n"
2036 "    foreach_api_reply_handler;\n"
2037 "#undef _\n\n"
2038 "}\n\n";
2039     
2040 void generate_jni_bottom_boilerplate(FILE *fp)
2041 {
2042     fputs (hookup_boilerplate, fp);
2043 }
2044
2045 void generate_python (YYSTYPE a1, FILE *fp)
2046 {
2047   node_t *np = (node_t *)a1;
2048   node_vft_t *vftp;
2049   fprintf (fp, "vppapidef = [\n");
2050   /* Walk the top-level node-list */
2051   while (np) {
2052     if (np->type == NODE_DEFINE && !(np->flags & NODE_FLAG_TYPEONLY)) {
2053       /* Yeah, this is pedantic */
2054       vftp = the_vft[np->type];
2055       vftp->generate(np, PYTHON_PASS, fp);
2056     }
2057     np = np->peer;
2058   }
2059   fprintf (fp, "\n]\n");
2060 }
2061
2062 void generate(YYSTYPE a1)
2063 {
2064     if (dump_tree) {
2065         dump((node_t *)a1);
2066     }
2067
2068     add_msg_ids(a1);
2069
2070     if (ofp) {
2071         generate_top_boilerplate(ofp);
2072
2073         generate_msg_ids(a1, ofp);
2074         generate_msg_names(a1, ofp);
2075         generate_typedefs(a1, ofp);
2076         generate_uniondefs(a1, ofp);
2077         generate_printfun(a1, ofp);
2078         generate_endianfun(a1, ofp);
2079         
2080         generate_bottom_boilerplate(ofp);
2081     }
2082
2083     if (javafp) {
2084         generate_java_top_boilerplate(javafp);
2085         generate_java_class_definition(a1, javafp);
2086         generate_java_bottom_boilerplate(javafp);
2087     }
2088     if (jnifp) {
2089         generate_jni_top_boilerplate(jnifp);
2090         generate_jni_reply_handler_list (a1, jnifp);
2091         generate_jni_code(a1, jnifp);
2092         generate_jni_bottom_boilerplate(jnifp);
2093     }
2094     if (pythonfp) {
2095       generate_python(a1, pythonfp);
2096     }
2097 }