Init basesystem source codes.
[staging/basesystem.git] / video_in_hal / otherservice / rpc_library / tool / apidef.cc
1 /*
2  * @copyright Copyright (c) 2016-2020 TOYOTA MOTOR CORPORATION.
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  *      http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16
17 /**
18  * @file apidef.cc
19  * @brief RPC tools--Main processing(Implementations of APIDef classes)
20  *
21  */
22 #include <stdio.h>
23 #include <stdlib.h>
24 #include <string.h>
25 #include <netinet/in.h>
26
27 #include <other_service/rpc.h>
28
29 #include "apidef.h"
30 #include "apidef.tab.h"
31
32 static APIDef *API_Def;
33
34 extern "C" {  // C interface functions
35
36 void
37 ApidefDefineId(const char *id) {
38   if (id != NULL) {
39     if (API_Def == NULL) {
40       API_Def = new APIDef();
41     }
42     API_Def->DefineId(id);
43   }
44 }
45
46 void
47 ApidefAddHeader(const char *filename) {
48   if (filename != NULL) {
49     if (API_Def == NULL) {
50       API_Def = new APIDef();
51     }
52     API_Def->AddHeader(filename);
53   }
54 }
55
56 int
57 ApidefPushFunctionArg(int arg_code, int buffer_bytes, int is_pointer,
58        int is_vararray, int is_array_size,
59        const char *var_type_name, int in_out,
60        const char *var_name) {
61   if (API_Def == NULL) {
62     API_Def = new APIDef();
63   }
64   return API_Def->AddFunctionArg(arg_code, buffer_bytes, is_pointer,
65              is_vararray, is_array_size,
66            var_type_name, in_out, var_name);
67 }
68
69 void
70 ApidefProcessFunction(const char *name) {
71   if (API_Def == NULL) {
72     API_Def = new APIDef();
73   }
74   API_Def->NameFunction(name);
75 }
76
77 void
78 ApidefListFunctions(int with_args) {
79   if (API_Def != NULL) {
80     API_Def->Print(with_args);
81   }
82 }
83
84 void
85 ApidefFreeAllocation(void) {
86   if (API_Def != NULL) {
87     delete API_Def;
88     API_Def = NULL;
89   }
90 }
91
92 int
93 ApidefMakeStubs(void) {
94   if (API_Def != NULL) {
95     API_Def->MakeStubs();
96     return 0;
97   } else {
98     return 1;
99   }
100 }
101
102 } // extern "C"
103
104 /*
105  * Retrieving Argument Names Without Decorators
106  */
107 void
108 Arg::GetUndecolatedName(string& name /* OUT */, int num) {
109   name = "v";
110   if (num > 0) {
111     /* Making Variable Names Sequential Numbers */
112     char num_str[5];
113     sprintf(num_str, "%d", num);
114     name += num_str;
115   } else {
116     /* Use a user-supplied pseudo-variable name */
117     name = m_name;
118   }
119 }
120
121 int
122 Arg::PrintUndecoratedName(fstream& out, int num) {
123   /* Pointer argument */
124   if (m_is_pointer) {
125     out << "*";
126   }
127
128   if (num > 0) {
129     /* Making Variable Names Sequential Numbers */
130     out << "v" << num;
131   } else {
132     /* Use a user-supplied pseudo-variable name */
133     out << m_name;
134   }
135
136   return 0;
137 }
138
139 /*
140  * Outputs one argument in a function prototype declaration
141  * out: Destination file
142  * num: Handling of Formal Argument Names
143  *      0 :Formal argument name specified in the API definition file
144  *      Non-zero: Use "v" + specified number(Examples: v1, v2, ...)
145  */
146 int
147 Arg::PrintPrototype(fstream& out, int num) {
148   const char *type = TypeCodeString(m_code);
149   if (type == NULL) {
150     type = m_type_name.c_str();
151   }
152   if (type == NULL) {
153     cout << "Internal Error Occurrence!!\n";
154     return 1;
155   }
156
157   /* Const non-output pointers */
158   if ((m_in_out & RPC_OUT_ARG) == 0 && (m_bytes != 0 || m_is_pointer != 0)) {
159     out << "const ";
160   }
161   out << type << " ";
162   if (m_is_pointer && m_bytes == 0) {/* Non-string pointer arguments */
163     out << "*";
164   }
165
166   if (num > 0) {/* Making variable names sequential numbers */
167     out << "v" << num;
168   } else {/* Use a user-supplied pseudo-variable name */
169     out << m_name;
170   }
171
172   /* Variable-length arrays */
173   if (m_is_vararray != 0) {
174     out << "/* VAR_ARRAY */";
175   }
176
177   /* Variable-length arrays length */
178   if (m_is_array_size != 0) {
179     out << "/* VAR_SIZE */";
180   }
181
182   /*
183    * Commenting on OUT/INOUT Arguments
184    * Maximum number of bytes of a string argument added to a comment
185    */
186   if ((m_in_out & RPC_OUT_ARG) != 0 || m_bytes != 0) {
187     out << "/* ";
188     if ((m_in_out & RPC_OUT_ARG) != 0) {
189       if ((m_in_out & RPC_IN_ARG) != 0) {
190         out << "IN";
191       }
192       out << "OUT ";
193     }
194     if (m_bytes) {
195       out << m_bytes << "Byte ";
196     }
197     out << "*/";
198   }
199
200   return 0;
201 }
202
203 int
204 Arg::CreateMarshallArgs(fstream& out, int num) {
205   return CreateMarshallArgs(out, num, (RPC_IN_ARG|RPC_OUT_ARG));
206 }
207
208 int
209 Arg::CreateMarshallArgs(fstream& out, int num, string &array_size_name) {
210   return CreateMarshallArgs(out, num, (RPC_IN_ARG|RPC_OUT_ARG), array_size_name);
211 }
212
213 int
214 Arg::CreateMarshallArgs(fstream& out, int num, int in_out) {
215   string dummy = "";
216   return CreateMarshallArgs(out, num, in_out, dummy);
217 }
218
219 /*
220  * The arguments to rpc_marshall_args() are generated for each API argument.
221  * for each API argument.
222  * out: Destination file
223  * num: Number given to the variable name of the argument (Examples: 1 for v1)
224  * in_out: Specifying the IN or OUT Attributes
225  *         Output only if the argument has the specified attribute
226  */
227 int
228 Arg::CreateMarshallArgs(fstream& out, int num, int in_out, string &array_size_name) {
229   if ((m_in_out & in_out) != 0) {
230     /*
231      * Collectively passes the argument type, pointer/non-pointer, IN/OUT attribute, 
232      * and the maximum number of bytes of the argument type to one integer.
233      */
234     RPC_marshall_flag flag;
235     flag.bits.code = m_code & ((1<<RPC_MARSHALL_FLAG_BITS_CODE)-1);
236     flag.bits.is_vararray = ((array_size_name.size() != 0) ? 1: 0) &
237                             ((1<<RPC_MARSHALL_FLAG_BITS_IS_VARARRAY)-1);
238     flag.bits.is_pointer = m_is_pointer & ((1<<RPC_MARSHALL_FLAG_BITS_IS_POINTER)-1);
239     flag.bits.in_out = m_in_out & ((1<<RPC_MARSHALL_FLAG_BITS_IN_OUT)-1);
240     flag.bits.bytes = (UINT16)(m_bytes);
241     char str[11];
242     sprintf(str, "0x%x", htonl(flag.all));
243     out << "\t\t\t" << str;
244
245     /*
246      * Add size of user-defined type to argument
247      */
248     if (m_code == rpc_USER_DEFINED) {
249       if (array_size_name.size() != 0) {
250         out << " + ntohs(sizeof(" << m_type_name << ") * " << array_size_name << ")";
251       } else {
252         out << " + ntohs(sizeof(" << m_type_name << "))";
253       }
254     } else if (array_size_name.size() != 0) {
255       out << " + ntohs(sizeof(" << TypeCodeString(m_code) << ") * " << array_size_name << ")";
256     }
257
258     out << ", v" << num;
259     return 1;
260   } else {
261     return 0;
262   }
263 }
264
265 int
266 Arg::CreateDemarshallArgs(fstream& out, int deliver_pointer, int num) {
267   return CreateDemarshallArgs(out, deliver_pointer, num, (RPC_IN_ARG|RPC_OUT_ARG));
268 }
269
270 int
271 Arg::CreateDemarshallArgs(fstream& out, int deliver_pointer, int num, string &array_size_name) {
272   return CreateDemarshallArgs(out, deliver_pointer, num, (RPC_IN_ARG|RPC_OUT_ARG), array_size_name);
273 }
274
275 int
276 Arg::CreateDemarshallArgs(fstream& out, int deliver_pointer, int num, int in_out) {
277   string dummy = "";
278   return CreateDemarshallArgs(out, deliver_pointer, num, in_out, dummy);
279 }
280
281 /*
282  * The arguments to rpc_demarshall_args() are generated for each API argument.
283  * for each API argument.
284  * out: Destination file
285  * deliver_pointer: Passing a Variable Pointer(non-0)
286  * num: Number given to the variable name of the argument (Examples: 1 for v1)
287  * in_out: Specifying the IN or OUT Attributes
288  *         Output only if the argument has the specified attribute
289  */
290 int
291 Arg::CreateDemarshallArgs(fstream& out, int deliver_pointer, int num, int in_out, string &array_size_name) {
292   if ((m_in_out & in_out) != 0) {
293     /*
294      * Collectively passes the argument type, pointer/non-pointer, IN/OUT attribute,
295      * and the maximum number of bytes of the argument type to one integer.
296      */
297     RPC_marshall_flag flag;
298     flag.bits.code = m_code & ((1<<RPC_MARSHALL_FLAG_BITS_CODE)-1);
299     flag.bits.is_vararray = ((array_size_name.size() != 0) ? 1: 0) &
300                             ((1<<RPC_MARSHALL_FLAG_BITS_IS_VARARRAY)-1);
301     flag.bits.is_pointer = m_is_pointer & ((1<<RPC_MARSHALL_FLAG_BITS_IS_POINTER)-1);
302     flag.bits.in_out = m_in_out & ((1<<RPC_MARSHALL_FLAG_BITS_IN_OUT)-1);
303     flag.bits.bytes = (UINT16)(m_bytes);
304     char str[11];
305     sprintf(str, "0x%x", htonl(flag.all));
306     out << "\t\t\t" << str;
307
308     /*
309      * Add size of user-defined type to argument
310      */
311     if (m_code == rpc_USER_DEFINED) {
312         out << " + ntohs(sizeof(" << m_type_name << "))";
313     }
314
315     out << ", ";
316     if (deliver_pointer) {
317       /* Pass a pointer */
318       out << "&";
319     }
320     out << "v" << num;
321     return 1;
322   } else {
323     return 0;
324   }
325 }
326
327 int
328 Function::AppendArg(int code, int bytes, int is_pointer,
329          int is_vararray, int is_array_size,
330          const char *var_type_name, int in_out, const char *var_name) {
331   if (NumOfArgs() >= RPC_MAX_API_ARG_NUM) {
332     cout << "Too many API function arguments.\n";
333     return -1;
334   }
335   Arg *a = new Arg(code, bytes, is_pointer, is_vararray, is_array_size,
336        var_type_name, in_out, var_name);
337   m_args.push_back(*a);
338   delete a;
339   return 0;
340 }
341
342 /*
343  * Generate prototype declarations for a single API function
344  * out: Destination file
345  */
346 int
347 Function::PrintPrototype(fstream& out, int server) {
348   int ret = 0;
349
350   const char *return_type
351     = server ? RPC_API_SERVER_RETURN : RPC_API_CLIENT_RETURN;
352 #ifdef DBG_ENABLE
353   if ((server) || (!rpc_log_enable)) {
354     out << return_type << " " << m_name << "(";
355   } else {
356     out << return_type << " __" << m_name << "(";
357   }
358 #else
359   out << return_type << " " << m_name << "(";
360 #endif
361
362   list<Arg>::size_type num_args = m_args.size();
363   if (num_args > 0) {
364     list<Arg>::iterator a;
365     a = m_args.begin();
366     for (list<Arg>::size_type i = 1; i <= num_args; ++i, ++a) {
367       a->PrintPrototype(out);
368 #ifdef DBG_ENABLE
369       if ((server) || (!rpc_log_enable)) {
370         if (i != num_args) {
371           out << ", ";
372         }
373       } else {
374   out << ", ";
375       }
376 #else
377       if (i != num_args) {
378   out << ", ";
379       }
380 #endif
381     }
382   } else {
383 #ifdef DBG_ENABLE
384     if ((server) || (!rpc_log_enable)) {
385       out << "void";
386     }
387 #else
388     out << "void";
389 #endif
390   }
391 #ifdef DBG_ENABLE
392   /* Debug information */
393   if ((!server) && (rpc_log_enable)) {
394     out << "const char *filename, const char *funcname, int line ";
395   }
396 #endif
397   out << ");\n";
398   return ret;
399 }
400
401 #ifdef DBG_ENABLE
402 int
403 Function::PrintMacro(fstream& out) {
404   int ret = 0;
405   out << "#define " << m_name << "(";
406
407   int num_args = m_args.size();
408   if (num_args > 0) {
409     int i;
410     char c;
411     for (i = 1, c = 'a'; i <= num_args; i++, c++) {
412       out << c;
413       if (i != num_args) {
414         out << ", ";
415       }
416     }
417     out << ") \\\n\t";
418
419     /* Entity */
420     out << "__" << m_name << "(";
421     for (i = 1, c = 'a'; i <= num_args; i++, c++) {
422       out << c << ", ";
423     }
424     out << "__FILE__, __func__, __LINE__)\n";
425   } else { /* Without arguments */
426     out << ") " << "__" << m_name << "(__FILE__, __func__, __LINE__)\n";
427   }
428
429   return ret;
430 }
431 #endif
432
433 int
434 APIDef::MakeHeaderFiles(int server) {
435   char filename[MAX_FILENAME_LEN+1];
436   sprintf(filename, "%s%s", m_lowerid.c_str(),
437     (server ? SERVER_HEADER_FILE : CLIENT_HEADER_FILE));
438   int ret = 0;
439
440   fstream out(filename, ios::out);
441   if (!out.is_open()) {
442     cout << "ERROR: File " << filename << " Could not open.\n";
443     return 1;
444   }
445   cout << "info: Header file " << filename << " Creating.\n";
446
447   const char *define_str =
448     server ? SERVER_HEADER_DEFINE : CLIENT_HEADER_DEFINE;
449   const char *title = server ? SERVER_HEADER_TITLE : CLIENT_HEADER_TITLE;
450
451   out << "#ifndef _" << m_lowerid << define_str << "\n";
452   out << "#define _" << m_lowerid << define_str << "\n";
453   out << "/*\n";
454   out << " * " << m_id << " " << title << " " << filename << "\n";
455   out << " *\n";
456   out << RPCTOOL_WARNING_STRING << "\n";
457   out << " */\n\n";
458
459   list<string>::iterator i;
460   for (i = m_headers.begin(); i != m_headers.end(); ++i) {
461     out << "#include <" << *i << ">\n";
462   }
463   out << "\n";
464
465   if (server) {
466
467     out << EXTERN_C_START << "\n";
468
469       out << RPC_API_DISPATCH_RETURN << " "
470     << m_id << RPC_API_DISPATCH_FUNC_FULL << ";\n";
471
472       out << "#ifdef RPC_DISPATCH_FUNC\n"
473     << "#undef RPC_DISPATCH_FUNC\n"
474     << "#define RPC_DISPATCH_FUNC " << m_id  << RPC_API_DISPATCH_FUNC_NAME
475     << "\n#else /* !RPC_DISPATCH_FUNC */\n"
476     << "#error \"Please include <rpc.h> first!!\"\n"
477     << "#endif /* !RPC_DISPATCH_FUNC */\n\n";
478
479     out << EXTERN_C_END << "\n";
480
481   }
482 #ifdef DBG_ENABLE
483   else if (rpc_log_enable) {
484     /* DEBUG INFORMATION EMBEDDED MACRO */
485     out << "/* Debug information embedded macro definition */\n";
486     list<Function>::iterator f;
487     for (f = m_funcs.begin(); f != m_funcs.end(); ++f) {
488       if (f->PrintMacro(out) != 0) {
489         ret = 1;
490         break;
491       }
492     }
493     out << "\n";
494   }
495 #endif
496
497   out << EXTERN_C_START << "\n";
498
499   out << "/* API definitions */\n";
500   list<Function>::iterator f;
501   for (f = m_funcs.begin(); f != m_funcs.end(); ++f) {
502     if (f->PrintPrototype(out, server) != 0) {
503       ret = 1;
504       break;
505     }
506   }
507   out << "\n";
508
509   out << EXTERN_C_END << "\n";
510
511   out << "#endif /* _" << m_lowerid << define_str << " */\n";
512   out.close();
513   return ret;
514 }
515
516 int
517 Function::PrintServerStub(fstream& out) {
518   int num_args = NumOfArgs();
519
520   out << "\tcase " << RPC_API_NUM_PREFIX << m_name << ": {\n";
521
522   list<Arg>::iterator a = m_args.begin();
523   for (int i = 1; i <= num_args; ++i, ++a) {
524     const char *type = TypeCodeString(a->Code());
525     if (type == NULL) {
526       type = (a->TypeName()).c_str();
527     }
528     if (type == NULL) {
529       return 1;
530     }
531     out << "\t\t" << type << " ";
532     if (a->Bytes() > 0 || a->IsPointer()) {/* Pointer-passing argument */
533       if (a->Bytes() > 0) {
534   out << "v" << i << " = NULL;\n";
535       } else if (a->IsPointer()) {
536   out << "*v" << i << " = NULL;\n";
537       }
538     } else {/* Pass-by-value argument */
539       out << "v" << i << ";\n";
540     }
541   }
542   if (num_args > 0) {
543     out << "\t\tif (" << RPC_DEMARSHALL_FUNCTION
544   << " (args_string, args_size, 1, " << num_args << ",\n";
545     /* In the STUB of servers for all pre-call demarshall */
546     /* Passing Pointers to Local Variables in Server STUB */
547     /* Pointer/ Buffer will alloc the required space in demarshall_arguments() */
548
549     a = m_args.begin();
550     for (int i = 1; i <= num_args; ++i, ++a) {
551       if (a->IsVararray() != 0) { /* Variable-length arrays */
552         a->CreateDemarshallArgs(out, 1, i, m_array_size_name);
553       } else {
554         a->CreateDemarshallArgs(out, 1, i);
555       }
556       if (i < num_args) {
557   out << ",";
558       }
559       out << "\n";
560     }
561     out << "\t\t   ) < 0) {\n";
562     out << "\t\t\tgoto _" << m_name << "_Error;\n";
563     out << "\t\t}\n";
564   }
565
566   out << "\t\tresult = " << m_name << "(";
567   for (int i = 1; i <= num_args; i++) {
568     out << "v" << i;
569     if (i < num_args) {
570       out << ", ";
571     }
572   }
573   out << ");\n";
574
575   int to_process = NumOfInOutArgs(RPC_OUT_ARG);
576   if (to_process > 0) {
577     /* Only OUT-arguments marshall after the server stub is called. */
578     out << "\t\t/*if (result == RPC_OK) {*/\n";
579     out << "\t\t    *ret_string = " << RPC_MARSHALL_FUNCTION
580   << "(ret_size, 0, " << to_process << ",\n";
581
582     a = m_args.begin();
583     int processed = 0;
584     int ret;
585     for (int i = 1; i <= num_args; ++i, ++a) {
586       if (a->IsVararray() != 0) { /* Variable-length arrays */
587   ret = a->CreateMarshallArgs(out, i, RPC_OUT_ARG, m_array_size_name);
588       } else {
589   ret = a->CreateMarshallArgs(out, i, RPC_OUT_ARG);
590       }
591       if (ret) {
592   processed++;
593   if (processed < to_process) {
594     out << ",";
595   }
596   out << "\n";
597       }
598     }
599     out << "\t\t   );\n"
600   << "\t\t    if (*ret_string == NULL) {\n"
601   << "\t\t\tresult = " << RPC_API_SERVER_ERROR << ";\n"
602   << "\t\t    }\n"
603   << "\t\t/*}*/\n";
604   }
605
606   if (num_args > 0) {
607     out << "_" << m_name << "_Error:\n";
608   }
609   int num_pointer_args = 0;
610   a = m_args.begin();
611   for (int i = 1; i <= num_args; ++i, ++a) {
612     if (a->Bytes() || a->IsPointer()) {
613       num_pointer_args++;
614     }
615   }
616   if (num_pointer_args > 0) {
617     int processed = 0;
618     out << "\t\t" << RPC_MARSHALL_FREE_FUNCTION
619   << "(" << num_pointer_args << ", ";
620     a = m_args.begin();
621     for (int i = 1; i <= num_args; ++i, ++a) {
622       if (a->Bytes() || a->IsPointer()) {
623   out << "v" << i;
624   processed++;
625   if (processed < num_pointer_args) {
626     out << ", ";
627   }
628       }
629     }
630     out << ");\n";
631   }
632   out << "\t\tbreak;\n\t}\n";
633   return 0;
634 }
635
636 int
637 APIDef::MakeServerStub(void) {
638   char filename[MAX_FILENAME_LEN+1];
639   sprintf(filename, "%s%s", m_lowerid.c_str(), SERVER_STUB_FILE);
640   int ret = 0;
641
642   fstream out(filename, ios::out);
643   if (!out.is_open()) {
644     cout << "File " << filename << " Could not open.\n";
645     return 1;
646   }
647   cout << "info: Stub file " << filename << " Creating.\n";
648
649   const char *title = SERVER_STUB_TITLE;
650
651   out << "/*\n";
652   out << " * " << m_id << " " << title << " " << filename << "\n";
653   out << " *\n";
654   out << RPCTOOL_WARNING_STRING << "\n";
655   out << " */\n";
656   out << "#include <" RPC_GLOBAL_HEADER_FILE << ">\n";
657   out << "#include \"" << m_lowerid << SERVER_HEADER_FILE << "\"\n";
658   out << "#include <netinet/in.h> /* for ntohs() */\n\n";
659
660   int api_num = 1;
661   list<Function>::iterator f;
662
663   for (f = m_funcs.begin(); f != m_funcs.end(); ++f, ++api_num) {
664     if (api_num >= (1<<16)) {
665       cout << "Too many API functions.(Up to 65535)\n";
666       return 1;
667     }
668     out << "#define " << RPC_API_NUM_PREFIX << f->Name()
669   << " " << api_num << "\n";
670   }
671   out << "\n";
672
673   out << "RPC_Result\n";
674   out << m_id << RPC_API_DISPATCH_FUNC_FULL << "\n";
675   out << "{\n";
676   out << "\tRPC_Result result = " << RPC_API_SERVER_ERROR << ";\n";
677   out << "\t*ret_string = NULL;\n";
678   out << "\tswitch(api_num) {\n";
679
680   for (f = m_funcs.begin(); f != m_funcs.end(); ++f) {
681     if (f->PrintServerStub(out) != 0) {
682       ret = 1;
683       break;
684     }
685   }
686
687   if (ret != 0) {
688     return ret;
689   }
690
691   out << "\tdefault:\n\t\tbreak;\n\t}\n";
692   out << "\treturn result;\n";
693   out << "}\n";
694
695   return ret;
696 }
697
698 int
699 Function::PrintClientStub(const char *moduleid, fstream& out) {
700   int ret = 0;
701
702   list<Arg>::iterator a;
703   /* Function Names and Arguments */
704   out << RPC_API_CLIENT_RETURN << "\n";
705 #ifdef DBG_ENABLE
706   if (rpc_log_enable) {
707     out << "__" << m_name << "(";
708   } else {
709     out << m_name << "(";
710   }
711 #else
712   out << m_name << "(";
713 #endif
714   int num_args = (int)(m_args.size());
715   if (num_args > 0) {
716     a = m_args.begin();
717     for (int i = 1; i <= num_args; ++i, ++a) {
718       if (a->PrintPrototype(out, i)) {
719   return 1;
720       }
721 #ifdef DBG_ENABLE
722       if (rpc_log_enable) {
723         out << ", ";
724       } else {
725         if (i < num_args) {
726           out << ", ";
727         }
728       }
729 #else
730       if (i < num_args) {
731         out << ", ";
732       }
733 #endif
734     }
735   } else {
736 #ifndef DBG_ENABLE
737     out << "void";
738 #else
739     if (!rpc_log_enable) {
740       out << "void";
741     }
742 #endif
743   }
744 #ifdef DBG_ENABLE
745   if (rpc_log_enable) {
746     out << "const char *filename, const char *funcname, int line ";
747   }
748 #endif
749   out << ")\n";
750
751   out << "{\n";
752
753   /* Contents of stub functions */
754
755   /* If the argument is present and the variable-length array does not exist */
756   if ((num_args > 0) && (m_array_size_pos == 0)) {
757     int is_exist_mytype = 0;
758     /* Restricted specifications */
759     out << "#ifdef RPC_STATIC_ASSERT\n";
760     out << "\tchar RPC_TOTAL_ARGSIZE_ERROR_in_" << m_name << "[\n";
761     out << "\t(((";
762     a = m_args.begin();
763     for (int i = 1; i <= num_args; ++i, ++a) {
764       if (i > 1) {
765         out << " + ";
766       }
767       out << "sizeof(";
768       a->PrintUndecoratedName(out, i);
769       out << ")";
770       /* For user types */
771       if ((!is_exist_mytype) && (NULL == TypeCodeString(a->Code()))) {
772         is_exist_mytype = 1;
773       }
774     }
775     out << ") > RPC_MAX_API_ARG_TOTAL_SIZE) ? -1: 1)\n";
776     out << "\t]__attribute__((unused));\n";
777
778     /* Have a user type */
779     if (is_exist_mytype) {
780       char c[3];
781       a = m_args.begin();
782       for (int i = 1; i <= num_args; ++i, ++a) {
783         if (NULL == TypeCodeString(a->Code())) {
784           sprintf(c, "%d", i);
785           out << "\tchar RPC_ARGSIZE_ERROR_in_" << m_name << "_arg" << c;
786           out << "[\n\t(sizeof(";
787           a->PrintUndecoratedName(out, i);
788           out << ") > RPC_MAX_API_ARG_SIZE) ? -1: 1\n";
789           out << "\t]__attribute__((unused));\n";
790         }
791       }
792     }
793
794     out << "#endif /* RPC_STATIC_ASSERT */\n";
795
796   }
797
798   out << "\tRPC_Result result = " << RPC_API_CLIENT_ERROR << ";\n";
799   out << "\tunsigned int args_size = 0, ret_size;\n";
800   out << "\tchar retcode[9];\n";
801
802   if (num_args > 0) {
803     /* Advance preparation==Marshalling of arguments */
804     out << "\tchar *args_string = " << RPC_MARSHALL_FUNCTION
805   << "(&args_size, 1, " << num_args << ",\n";
806     /* In the clients STUB for all pre-call marshall */
807     a = m_args.begin();
808     for (int i = 1; i <= num_args; ++i, ++a) {
809       if (a->IsVararray() != 0) { /* Variable-length arrays */
810   a->CreateMarshallArgs(out, i, m_array_size_name);
811       } else {
812         a->CreateMarshallArgs(out, i);
813       }
814       if (i < num_args) {
815   out << ",";
816       }
817       out << "\n";
818     }
819     out << "\t);\n";
820     out << "\tif (args_string == NULL) {\n"
821   << "\t\tgoto _" << m_name << "_Error;\n\t}\n";
822   } else {
823     out << "\tchar *args_string = NULL;\n";
824   }
825
826 #ifdef DBG_ENABLE
827   if (rpc_log_enable) {
828     out << "\tif (" << moduleid << "_record_dbg_log(filename, funcname, line, \"";
829     out << m_name << "\") != 0) {\n";
830     out << "\t\tgoto _" << m_name << "_Error;\n\t}\n";
831   }
832 #endif
833
834   /* RPC API call */
835   out << "\tchar *ret_string = NULL; /* pgr0431 */\n";
836 #ifdef RPC_STRING_ID
837   out << "\tresult=RPC_API_call(\"" << moduleid << "\", ";
838 #else
839   out << "\tresult=RPC_API_call(" << moduleid << "_RPC_ID, ";
840 #endif
841   out << RPC_API_NUM_PREFIX << m_name;
842   out << ", args_string, args_size, &ret_string, &ret_size);\n";
843
844   // 2007.08.25 To avoid over run within the sscanf
845   // Locally copies strings needed for determining return values and uses strtol instead of sscanf
846   // (Since there is no guarantee that the byte sequence to be grabbed by communication is 0-terminated)
847   out << "\n"
848       << "\tif (result == RPC_OK && ret_string != NULL) {\n"
849       << "\t    strncpy(retcode, ret_string, 8);\n"
850       << "\t    retcode[8] = '\\0';\n"
851       << "\t    result = (RPC_Result)strtoul(retcode, NULL, 16);\n";
852
853   /* Post-processing==Arguments de-marshalling, free() */
854   int num_of_out_args = NumOfInOutArgs(RPC_OUT_ARG);
855   if (num_of_out_args > 0) {
856     out << "\t    if (" << RPC_DEMARSHALL_FUNCTION
857   << "(ret_string + RPC_RETCODE_LEN, ret_size - RPC_RETCODE_LEN, 0, "
858   << num_of_out_args << ",\n";
859
860     a = m_args.begin();
861     int processed = 0;
862     int ret;
863     for (int i = 1; i <= num_args; ++i, ++a) {
864       if (a->IsVararray() != 0) { /* Variable-length arrays */
865         ret = a->CreateDemarshallArgs(out, 0, i, RPC_OUT_ARG, m_array_size_name);
866       } else {
867         ret = a->CreateDemarshallArgs(out, 0, i, RPC_OUT_ARG);
868       }
869       if (ret) {
870   processed++;
871   if (processed < num_of_out_args) {
872     out << ",";
873   }
874   out << "\n";
875       }
876     }
877     out << "\t   ) < 0) {\n"
878   << "\t\tresult = " << RPC_API_CLIENT_ERROR << ";\n"
879   << "\t    }\n";
880   }
881
882   out << "\t} else {\n\t    //result = " << RPC_API_CLIENT_ERROR << ";\n"
883       << "\t}\n";
884
885   out << "\t" << RPC_RETURN_FREE_FUNCTION << "(ret_string);\n";
886   out << "\t" << RPC_MARSHALL_FREE_FUNCTION << "(1, args_string);\n";
887
888   /* END, RETURN */
889 #ifndef DBG_ENABLE
890   if (num_args)
891 #else
892   if ((num_args)||(rpc_log_enable))
893 #endif
894   {
895     out << "_" << m_name << "_Error:\n";
896   }
897
898   out << "\treturn result;\n}\n";
899
900   return ret;
901 }
902
903 int
904 APIDef::MakeClientStub(void) {
905   char filename[MAX_FILENAME_LEN+1];
906   sprintf(filename, "%s%s", m_lowerid.c_str(), CLIENT_STUB_FILE);
907   int ret = 0;
908
909   fstream out(filename, ios::out);
910   if (!out.is_open()) {
911     cout << "File " << filename << " Could not open.\n";
912     return 1;
913   }
914   cout << "info: Stub file " << filename << " Creating.\n";
915
916   const char *title = CLIENT_STUB_TITLE;
917
918   out << "/*\n";
919   out << " * " << m_id << " " << title << " " << filename << "\n";
920   out << " *\n";
921   out << RPCTOOL_WARNING_STRING << "\n";
922   out << " */\n";
923   out << "#include <" RPC_GLOBAL_HEADER_FILE << ">\n";
924   out << "#include <" << m_lowerid << CLIENT_HEADER_FILE << ">\n\n";
925   out << "#include <stdio.h> /* for sscanf() */\n";
926   out << "#include <stdlib.h> /* for getenv() */\n";
927   out << "#include <string.h> /* for strncpy() */\n";
928   out << "#include <netinet/in.h> /* for ntohs() */\n\n";
929
930   int api_num = 1;
931   list<Function>::iterator f;
932   for (f = m_funcs.begin(); f != m_funcs.end(); ++f, ++api_num) {
933     if (api_num >= (1<<16)) {
934       cout << "Too many API functions.(Up to 65535)\n";
935       return 1;
936     }
937     out << "#define " << RPC_API_NUM_PREFIX << f->Name()
938   << " " << api_num << "\n";
939   }
940   out << "\n";
941
942   /* Specification Restriction Debug Constants */
943   out << "/*#define RPC_STATIC_ASSERT*/\n";
944   out << "\n";
945
946 #ifdef DBG_ENABLE
947   if (rpc_log_enable) {
948     int m_id_work_cnt;
949     string m_id_work = m_id;
950     for (m_id_work_cnt = 0; m_id_work_cnt < m_id_work.length(); m_id_work_cnt++) {
951       m_id_work[m_id_work_cnt] = toupper(m_id_work[m_id_work_cnt]);
952     }
953     out << "int\n" << m_id << "_record_dbg_log(const char *filename, " <<
954     "const char *funcname, int line, const char *apiname)\n";
955     out << "{\n\t";
956     out << "if (getenv(\"" << m_id_work << "_RPC_LOG\") != NULL) {\n\t\t";
957     out << "return RPC_record_dbg_log(filename, funcname, line, apiname);\n\t";
958     out << "}\n\t";
959     out << "return 0;\n";
960     out << "}\n\n";
961   }
962 #endif
963
964   /* API definitions */
965   for (f = m_funcs.begin(); f != m_funcs.end(); ++f) {
966     if (f->PrintClientStub(m_id.c_str(), out) != 0) {
967       ret = 1;
968       break;
969     }
970   }
971   return ret;
972 }
973
974 int
975 Arg::IsArraySize(void) {
976   if (m_is_array_size != 0) {
977     if (IsTypeCodeNumeric(m_code) == 1) {
978       return 1;
979     } else {
980       cout << "Variable-length array length specification variables must be integers.\n";
981       return -1;
982     }
983   }
984   return 0;
985 }
986
987 int
988 Function::CheckFuncArraySize(void) {
989   int num_args = (int)(m_args.size());
990   list<Arg>::iterator a;
991   a = m_args.begin();
992   for (int i = 1; i <= num_args; ++i, ++a) {
993     int ret = a->IsArraySize();
994     if (ret > 0) {
995       if (m_array_size_pos != 0)
996       {
997         cout << "Two or more variable array length specification arguments exist.\n";
998         return 1;
999       }
1000       m_array_size_pos = i;
1001       a->GetUndecolatedName(m_array_size_name, i);
1002     } else if (ret < 0) {
1003       return 1;
1004     }
1005   }
1006   return 0;
1007 }
1008
1009 int
1010 APIDef::CheckAllArraySize(void) {
1011   list<Function>::iterator f;
1012   for (f = m_funcs.begin(); f != m_funcs.end(); ++f) {
1013     if (f->CheckFuncArraySize() != 0) {
1014       return 1;
1015     }
1016   }
1017   return 0;
1018 }
1019
1020 int
1021 APIDef::MakeStubs(void) {
1022   if (m_id.size() == 0) {
1023     cout << "The module name is not specified.\n";
1024     return 1;
1025   }
1026
1027   if (m_id.size() > MAX_FILENAME_LEN - strlen(SERVER_STUB_FILE)) {
1028     cout << "The module name is too long.\n";
1029     return 1;
1030   }
1031
1032   /* Pre-examine the ARRAYSIZE specification */
1033   //cout << "<check_all_array_size>\n";
1034   if (CheckAllArraySize() != 0) {
1035     return 1;
1036   }
1037
1038   //cout << "<MakeHeaderFiles(0)>\n";
1039   if (MakeHeaderFiles(1) != 0) {
1040     return 1;
1041   }
1042
1043   //cout << "<MakeHeaderFiles(1)>\n";
1044   if (MakeHeaderFiles(0) != 0) {
1045     return 1;
1046   }
1047
1048   if (MakeServerStub() != 0) {
1049     return 1;
1050   }
1051
1052   if (MakeClientStub() != 0) {
1053     return 1;
1054   }
1055
1056   return 0;
1057 }
1058
1059 void
1060 Arg::Print(void) {
1061   cout << "\t";
1062   if (m_name.size() > 0) {
1063     cout << "Variable name=" << m_name << " ";
1064   }
1065   cout << "Type=" << TypeCodeString(m_code) << "In bytes=" << m_bytes << " ";
1066   if (m_is_pointer) {
1067     cout << "Pointer ";
1068   }
1069   if ((m_in_out & RPC_OUT_ARG) != 0) {
1070     cout << "Output ";
1071   }
1072   cout << "\n";
1073 }
1074
1075 void
1076 Function::Print(int with_args) {
1077   printf("Function name=%s\n", m_name.c_str());
1078   if (with_args) {
1079     list<Arg>::iterator a;
1080     for (a = m_args.begin(); a != m_args.end(); ++a) {
1081       a->Print();
1082     }
1083   }
1084 }
1085
1086 void
1087 APIDef::Print(int with_args) {
1088   list<Function>::iterator f;
1089   for (f = m_funcs.begin(); f != m_funcs.end(); ++f) {
1090     f->Print(with_args);
1091   }
1092 }
1093
1094 void
1095 APIDef::IdTolower(void) {
1096   char *lower = new char[m_id.size() + 1];
1097   strcpy(lower, m_id.c_str());
1098   char *p;
1099   for (p = lower; *p; p++) {
1100     *p = (char)(tolower(*p));
1101   }
1102   m_lowerid = lower;
1103   delete[] lower;
1104 }