1#!/usr/bin/env python3
2# -*- coding: utf-8 -*-
3
4# Copyright (c) 2024 Huawei Device Co., Ltd.
5# Licensed under the Apache License, Version 2.0 (the "License");
6# you may not use this file except in compliance with the License.
7# You may obtain a copy of the License at
8#
9#     http://www.apache.org/licenses/LICENSE-2.0
10#
11# Unless required by applicable law or agreed to in writing, software
12# distributed under the License is distributed on an "AS IS" BASIS,
13# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14# See the License for the specific language governing permissions and
15# limitations under the License.
16
17from __future__ import absolute_import
18
19import os
20import file_parser
21import make_file_base
22
23# pylint:disable=huawei-redefined-outer-name
24
25# ------------------------------------------------------------------------------------------------------#
26
27def make_capi_static_funcs(funcs, indent, defined_names, translate_map):
28  new_list = []
29  old_list = make_file_base.get_func_name_list(funcs)
30
31  result = ''
32  for func in funcs:
33    if func.get_retval().get_type().is_result_string():
34      result += indent + '// The resulting string must be freed by calling cef_string_userfree_free().\n'
35
36    suffix = ''
37    new_list = make_file_base.get_func_name_count(func.get_capi_name(), old_list, new_list)
38    if new_list.count(func.get_capi_name()) != 0:
39      suffix = str(new_list.count(func.get_capi_name()))
40
41    result += '\n' + indent + 'ARK_WEB_EXPORT ' + func.get_capi_proto(defined_names, suffix) + ';\n'
42
43  return result
44
45# ------------------------------------------------------------------------------------------------------#
46
47def make_capi_class_funcs(funcs, indent, defined_names, translate_map):
48  new_list = []
49  old_list = make_file_base.get_func_name_list(funcs)
50
51  result = ''
52  for func in funcs:
53    result += '\n'
54    if func.get_retval().get_type().is_result_string():
55      result += indent + '// The resulting string must be freed by calling cef_string_userfree_free().\n'
56
57    suffix = ''
58    new_list = make_file_base.get_func_name_count(func.get_capi_name(), old_list, new_list)
59    if new_list.count(func.get_capi_name()) != 0:
60      suffix = str(new_list.count(func.get_capi_name()))
61    elif file_parser.check_func_name_is_key_work(func.get_capi_name()):
62      suffix = '0'
63
64    parts = func.get_capi_parts()
65    result += indent+parts['retval']+' (ARK_WEB_CALLBACK *'+parts['name'] + suffix + \
66              ')('+', '.join(parts['args'])+');\n'
67
68  return result
69
70# ------------------------------------------------------------------------------------------------------#
71
72def make_capi_include_file(clses, header, file_name, all_declares):
73  result = ''
74
75  # identify all includes and forward declarations
76  internal_includes = set([])
77  translated_includes = set([])
78  for cls in clses:
79    includes = cls.get_includes()
80    for include in includes:
81      translated_includes.add(include)
82
83    declares = cls.get_forward_declares()
84    for declare in declares:
85      declare_cls = header.get_class(declare)
86      if declare_cls is None:
87        raise Exception('Unknown class: %s' % declare)
88
89      all_declares.add(declare_cls.get_capi_name())
90
91  # output translated includes
92  flag = True
93  if len(translated_includes) > 0:
94    sorted_includes = sorted(translated_includes)
95    for include in sorted_includes:
96      if include == 'base/include/ark_web_base_ref_counted' and flag:
97        flag = False
98        result += '#include "base/capi/ark_web_base_ref_counted_capi.h"\n'
99      elif include == 'base/include/ark_web_types' or include == 'ohos_nweb/include/ark_web_value' \
100          or include == 'ohos_nweb/include/ark_web_message' or include == 'ohos_nweb/include/ark_web_nweb_structs' \
101          or include == 'ohos_adapter/include/ark_web_adapter_structs' or include.endswith('_vector'):
102        result += '#include "' + include + '.h"\n'
103      else:
104        if include.startswith('ohos_nweb/include/') and flag:
105          flag = False
106          result += '#include "base/capi/ark_web_base_ref_counted_capi.h"\n'
107        result += '#include "' + include.replace('/include/', '/capi/') + '_capi.h"\n'
108  else:
109    result += '#include "base/capi/ark_web_base_ref_counted_capi.h"\n'
110
111  # output internal includes
112  if len(internal_includes) > 0:
113    sorted_includes = sorted(internal_includes)
114    for include in sorted_includes:
115      result += '#include "include/' + include + '.h"\n'
116
117  return result
118
119# ------------------------------------------------------------------------------------------------------#
120
121def make_capi_class_body(clses, header, file_name, all_declares):
122  result = ''
123
124  # output forward declarations
125  if len(all_declares) > 0:
126    sorted_declares = sorted(all_declares)
127    for declare in sorted_declares:
128      result += '\n' + \
129                'typedef struct _' + declare + ' ' + declare + ';\n'
130
131  # structure names that have already been defined
132  defined_names = header.get_defined_structs()
133
134  # map of strings that will be changed in C++ comments
135  translate_map = header.get_capi_translations()
136
137  # output classes
138  for cls in clses:
139    # virtual functions are inside the structure
140    capi_name = cls.get_capi_name()
141    result += '\n' + \
142              'typedef struct _' + capi_name + ' {\n' + \
143              '  /**\n' + \
144              '   * @brief Base structure.\n' + \
145              '   */\n' + \
146              '  ' + cls.get_parent_capi_name() + ' base;\n'
147    funcs = cls.get_virtual_funcs()
148    result += make_capi_class_funcs(funcs, '  ', defined_names, translate_map)
149    result += '} ' + capi_name + ';\n'
150
151    defined_names.append(capi_name)
152
153    # static functions become global
154    funcs = cls.get_static_funcs()
155    if len(funcs) > 0:
156      result += make_capi_static_funcs(funcs, '', defined_names, translate_map)
157
158  # output global functions
159  funcs = header.get_funcs(file_name)
160  if len(funcs) > 0:
161    result += make_capi_static_funcs(funcs, '', defined_names, translate_map) + '\n'
162
163  return result
164
165# ------------------------------------------------------------------------------------------------------#
166
167def make_capi_header_file(header, dir_path, dir_name, file_name):
168  # header string
169  content = make_file_base.get_copyright()
170
171  content += \
172"""
173#ifndef $GUARD$
174#define $GUARD$
175#pragma once
176"""
177  content += '\n'
178
179  clses = header.get_classes(file_name)
180
181  all_declares = set([])
182  content += make_capi_include_file(clses, header, file_name, all_declares)
183
184  content += \
185"""
186#ifdef __cplusplus
187extern "C" {
188#endif
189"""
190
191  content += make_capi_class_body(clses, header, file_name, all_declares)
192
193  # footer string
194  content += \
195"""
196#ifdef __cplusplus
197}
198#endif
199
200#endif // $GUARD$
201"""
202
203  # add the guard string
204  guard = file_name.replace('/', '_').replace('.', '_capi_').upper() + '_'
205  content = content.replace('$GUARD$', guard)
206
207  absolute_dir = os.path.join(os.path.join(dir_path, dir_name), 'capi')
208  absolute_path = os.path.join(absolute_dir, file_name.replace('.', '_capi.'))
209
210  return (content, absolute_path)
211
212