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