diff --git a/.gitignore b/.gitignore index 3d4ae48b..57990d8c 100644 --- a/.gitignore +++ b/.gitignore @@ -1,6 +1,32 @@ # See https://dart.dev/guides/libraries/private-files -# Files and directories created by pub +# Files and directories created by pub. .dart_tool/ .packages pubspec.lock + +# Directory created by dartdoc. +# If you don't generate documentation locally you can remove this line. +doc/api/ + +# Avoid committing generated Javascript files: +*.dart.js +*.info.json # Produced by the --dump-info flag. +*.js # When generated by dart2js. Don't specify *.js if your + # project includes source files written in JavaScript. +*.js_ +*.js.deps +*.js.map + +# Generated shared libraries. +*.so +*.so.* +*.dylib +*.dll + +# Directory for quick experiments. +experiments/ + +# Files generated by tests for debugging purposes. +test/debug_generated/* +!test/debug_generated/readme.md diff --git a/AUTHORS b/AUTHORS index 846e4a15..4f334e85 100644 --- a/AUTHORS +++ b/AUTHORS @@ -4,3 +4,5 @@ # Name/Organization Google LLC + +Prerak Mann diff --git a/CHANGELOG.md b/CHANGELOG.md new file mode 100644 index 00000000..8fcd2968 --- /dev/null +++ b/CHANGELOG.md @@ -0,0 +1,5 @@ +# 0.1.0 +- Initial release supporing binding generation for Functions, Structs, Enums. +- Glob support for specifying headers. +- HeaderFilter - Include/Exclude declarations from specific header files. +- Filters - Include/Exclude function, structs and enum declarations using Regexp or Name matching. diff --git a/README.md b/README.md index 3c017879..7eaeb2ba 100644 --- a/README.md +++ b/README.md @@ -2,3 +2,69 @@ Experimental generator for [FFI](https://dart.dev/guides/libraries/c-interop) bindings. + +## Example + +For some header file _example.h_: +```C +int sum(int a, int b); +``` +Add configurations to Pubspec File: +```yaml +ffigen: + output: 'generated_bindings.dart' + headers: + - 'example.h' +``` +Output (_generated_bindings.dart_). +```dart +DynamicLibrary _dylib; + +/// Initialises dynamic library +void init(DynamicLibrary dylib) { + _dylib = dylib; +} + +int sum(int a,int b) { + return _sum(a,b); +} + +final _dart_sum _sum = _dylib.lookupFunction<_c_sum, _dart_sum>('sum'); + +typedef _c_sum = Int32 Function(Int32 a,Int32 b); + +typedef _dart_sum = int Function(int a,int b); +``` +## Using this package +- clone/download this repository. +- Build it (see [building](#building)). +- Add this package as dev_dependency in your `pubspec.yaml`. +- Configurations must be provided in the pubspec.yaml file under the key `ffigen` (or directly under a seperate yaml file which when u specify it passing `--config filename` when running the tool) +- Run the tool- `pub run ffigen:generate`. + +## Building +A dynamic library for a wrapper to libclang needs to be generated as it is used by the parser submodule. + +#### ubuntu/linux +1. Install libclangdev - `sudo apt-get install libclang-dev`. +2. `cd tool/wrapped_libclang`, then run `dart build.dart`. + +#### Windows +1. Install Visual Studio with C++ development support. +2. Install LLVM. +3. `cd tool\wrapped_libclang`, then run `dart build.dart`. + +#### MacOS +1. Install LLVM. +2. `cd tool/wrapped_libclang`, then run `dart build.dart`. + +## Trying out examples +1. `cd examples/`, Run `pub get`. +2. Run `pub run ffigen:generate`. + +## Running Tests +Dynamic library for some tests need to be built before running the examples. +1. `cd test/native_functions_test`. +2. Run `dart build_test_dylib.dart`. + +Run tests from the root of the package with `pub run test`. diff --git a/analysis_options.yaml b/analysis_options.yaml index 108d1058..fb0e8678 100644 --- a/analysis_options.yaml +++ b/analysis_options.yaml @@ -1 +1,19 @@ +# Copyright (c) 2020, the Dart project authors. Please see the AUTHORS file +# for details. All rights reserved. Use of this source code is governed by a +# BSD-style license that can be found in the LICENSE file. + include: package:pedantic/analysis_options.yaml + +analyzer: + strong-mode: + implicit-casts: false + implicit-dynamic: false + errors: + omit_local_variable_types: ignore + +linter: + rules: + - directives_ordering + - prefer_final_fields + - prefer_final_locals + - prefer_final_in_for_each diff --git a/bin/generate.dart b/bin/generate.dart new file mode 100644 index 00000000..7f29f2a7 --- /dev/null +++ b/bin/generate.dart @@ -0,0 +1,176 @@ +// Copyright (c) 2020, the Dart project authors. Please see the AUTHORS file +// for details. All rights reserved. Use of this source code is governed by a +// BSD-style license that can be found in the LICENSE file. + +// Executable script to generate bindings for some C library. +import 'dart:io'; + +import 'package:args/args.dart'; +import 'package:ffigen/src/config_provider.dart'; +import 'package:ffigen/src/header_parser.dart' as parser; +import 'package:logging/logging.dart'; +import 'package:yaml/yaml.dart' as yaml; + +var _logger = Logger('generate.dart'); + +void main(List args) { + // Parses the cmd args. + final result = getArgResults(args); + + // Setup logging level and printing. + setupLogger(result); + + // Create a config object. + final config = getConfig(result); + + // Parse the bindings according to config object provided. + final library = parser.parse(config); + + if (config.sort) { + library.sort(); + } + + // Generate file for the parsed bindings. + final gen = File(config.output); + library.generateFile(gen); + _logger.info('Finished, Bindings generated in ${gen?.absolute?.path}'); +} + +Config getConfig(ArgResults result) { + _logger.info('Running in ${Directory.current}'); + + if (result.wasParsed('config')) { + return getConfigFromCustomYaml(result['config'] as String); + } else { + return getConfigFromPubspec(); + } +} + +/// Extracts configuration from pubspec file. +Config getConfigFromPubspec() { + final pubspecName = 'pubspec.yaml'; + final configKey = 'ffigen'; + + final pubspecFile = File(pubspecName); + + if (!pubspecFile.existsSync()) { + _logger.severe( + 'Error: $pubspecName not found, please run this tool from the root of your package.'); + exit(1); + } + + // Casting this because pubspec is expected to be a YamlMap. + + // Throws a [YamlException] if it's unable to parse the Yaml. + final bindingsConfigMap = + yaml.loadYaml(pubspecFile.readAsStringSync())[configKey] as yaml.YamlMap; + + if (bindingsConfigMap == null) { + _logger.severe("Couldn't find an entry for '$configKey' in $pubspecName."); + exit(1); + } + return Config.fromYaml(bindingsConfigMap); +} + +/// Extracts configuration from a custom yaml file. +Config getConfigFromCustomYaml(String yamlPath) { + final yamlFile = File(yamlPath); + + if (!yamlFile.existsSync()) { + _logger.severe('Error: $yamlPath not found.'); + exit(1); + } + + // Throws a [YamlException] if it's unable to parse the Yaml. + final bindingsConfigMap = + yaml.loadYaml(yamlFile.readAsStringSync()) as yaml.YamlMap; + + return Config.fromYaml(bindingsConfigMap); +} + +/// Parses the cmd line arguments. +ArgResults getArgResults(List args) { + final parser = ArgParser(allowTrailingOptions: true); + + parser.addSeparator( + 'FFIGEN: Generate dart bindings from C header files\nUsage:'); + parser.addOption( + 'config', + help: 'path to Yaml file containing configurations if not in pubspec.yaml', + ); + parser.addOption( + 'verbose', + abbr: 'v', + defaultsTo: 'info', + allowed: [ + 'all', + 'fine', + 'info', + 'warning', + 'severe', + ], + ); + parser.addFlag( + 'help', + abbr: 'h', + help: 'prints this usage', + negatable: false, + ); + + ArgResults results; + try { + results = parser.parse(args); + + if (results.wasParsed('help')) { + print(parser.usage); + exit(0); + } + } catch (e) { + print(e); + print(parser.usage); + exit(1); + } + + return results; +} + +/// Sets up the logging level and printing. +void setupLogger(ArgResults result) { + if (result.wasParsed('verbose')) { + switch (result['verbose'] as String) { + case 'all': + // Logs everything, the entire AST touched by our parser. + Logger.root.level = Level.ALL; + break; + case 'fine': + // Logs AST parts relevant to user (i.e those included in filters). + Logger.root.level = Level.FINE; + break; + case 'info': + // Logs relevant info for general user (default). + Logger.root.level = Level.INFO; + break; + case 'warning': + // Logs warnings for relevant stuff. + Logger.root.level = Level.WARNING; + break; + case 'severe': + // Logs severe warnings and errors. + Logger.root.level = Level.SEVERE; + break; + } + // Setup logger for printing (if verbosity was set by user). + Logger.root.onRecord.listen((record) { + print('${record.level.name.padRight(8)}: ${record.message}'); + }); + } else { + // Setup logger for printing (if verbosity was not set by user). + Logger.root.onRecord.listen((record) { + if (record.level.value > Level.INFO.value) { + print(' ${record.level.name.padRight(8)}: ${record.message}'); + } else { + print(record.message); + } + }); + } +} diff --git a/example/c_json/.gitignore b/example/c_json/.gitignore new file mode 100644 index 00000000..1b051642 --- /dev/null +++ b/example/c_json/.gitignore @@ -0,0 +1,11 @@ +# Files and directories created by pub. +.dart_tool/ +.packages +# Remove the following pattern if you wish to check in your lock file. +pubspec.lock + +# Conventional directory for build outputs. +build/ + +# Directory created by dartdoc. +doc/api/ diff --git a/example/c_json/README.md b/example/c_json/README.md new file mode 100644 index 00000000..9ba9d436 --- /dev/null +++ b/example/c_json/README.md @@ -0,0 +1,25 @@ +# cJson example + +Demonstrates generation of bindings for a C library called +[cJson](https://github.com/DaveGamble/cJSON) and then using these bindings +to parse some json. + +## Building the cJson dynamic library +From the root of this repository - +``` +cd third_party/cjson_library +cmake . +make +``` + +## Generating bindings +At the root of this example (`example/c_json`), run - +``` +pub run ffigen:generate +``` +This will generate bindings in a file: [cjson_generated_bindings.dart](./cjson_generated_bindings.dart) + +## Running the example +``` +dart main.dart +``` diff --git a/example/c_json/cjson_generated_bindings.dart b/example/c_json/cjson_generated_bindings.dart new file mode 100644 index 00000000..1cf00a3d --- /dev/null +++ b/example/c_json/cjson_generated_bindings.dart @@ -0,0 +1,1691 @@ +/// AUTO GENERATED FILE, DO NOT EDIT. +/// +/// Generated by `package:ffigen`. +import 'dart:ffi' as ffi; + +/// Holds the Dynamic library. +ffi.DynamicLibrary _dylib; + +/// Initialises the Dynamic library. +void init(ffi.DynamicLibrary dylib) { + _dylib = dylib; +} + +class cJSON extends ffi.Struct { + ffi.Pointer next; + + ffi.Pointer prev; + + ffi.Pointer child; + + @ffi.Int32() + int type; + + ffi.Pointer valuestring; + + @ffi.Int32() + int valueint; + + @ffi.Double() + double valuedouble; + + ffi.Pointer string; +} + +typedef _typedefC_noname_1 = ffi.Pointer Function( + ffi.Uint64, +); + +typedef _typedefC_noname_2 = ffi.Void Function( + ffi.Pointer, +); + +class cJSON_Hooks extends ffi.Struct { + ffi.Pointer> malloc_fn; + + ffi.Pointer> free_fn; +} + +ffi.Pointer cJSON_Version() { + return _cJSON_Version(); +} + +final _dart_cJSON_Version _cJSON_Version = _dylib + .lookupFunction<_c_cJSON_Version, _dart_cJSON_Version>('cJSON_Version'); + +typedef _c_cJSON_Version = ffi.Pointer Function(); + +typedef _dart_cJSON_Version = ffi.Pointer Function(); + +void cJSON_InitHooks( + ffi.Pointer hooks, +) { + return _cJSON_InitHooks( + hooks, + ); +} + +final _dart_cJSON_InitHooks _cJSON_InitHooks = + _dylib.lookupFunction<_c_cJSON_InitHooks, _dart_cJSON_InitHooks>( + 'cJSON_InitHooks'); + +typedef _c_cJSON_InitHooks = ffi.Void Function( + ffi.Pointer hooks, +); + +typedef _dart_cJSON_InitHooks = void Function( + ffi.Pointer hooks, +); + +ffi.Pointer cJSON_Parse( + ffi.Pointer value, +) { + return _cJSON_Parse( + value, + ); +} + +final _dart_cJSON_Parse _cJSON_Parse = + _dylib.lookupFunction<_c_cJSON_Parse, _dart_cJSON_Parse>('cJSON_Parse'); + +typedef _c_cJSON_Parse = ffi.Pointer Function( + ffi.Pointer value, +); + +typedef _dart_cJSON_Parse = ffi.Pointer Function( + ffi.Pointer value, +); + +ffi.Pointer cJSON_ParseWithOpts( + ffi.Pointer value, + ffi.Pointer> return_parse_end, + int require_null_terminated, +) { + return _cJSON_ParseWithOpts( + value, + return_parse_end, + require_null_terminated, + ); +} + +final _dart_cJSON_ParseWithOpts _cJSON_ParseWithOpts = + _dylib.lookupFunction<_c_cJSON_ParseWithOpts, _dart_cJSON_ParseWithOpts>( + 'cJSON_ParseWithOpts'); + +typedef _c_cJSON_ParseWithOpts = ffi.Pointer Function( + ffi.Pointer value, + ffi.Pointer> return_parse_end, + ffi.Int32 require_null_terminated, +); + +typedef _dart_cJSON_ParseWithOpts = ffi.Pointer Function( + ffi.Pointer value, + ffi.Pointer> return_parse_end, + int require_null_terminated, +); + +ffi.Pointer cJSON_Print( + ffi.Pointer item, +) { + return _cJSON_Print( + item, + ); +} + +final _dart_cJSON_Print _cJSON_Print = + _dylib.lookupFunction<_c_cJSON_Print, _dart_cJSON_Print>('cJSON_Print'); + +typedef _c_cJSON_Print = ffi.Pointer Function( + ffi.Pointer item, +); + +typedef _dart_cJSON_Print = ffi.Pointer Function( + ffi.Pointer item, +); + +ffi.Pointer cJSON_PrintUnformatted( + ffi.Pointer item, +) { + return _cJSON_PrintUnformatted( + item, + ); +} + +final _dart_cJSON_PrintUnformatted _cJSON_PrintUnformatted = _dylib + .lookupFunction<_c_cJSON_PrintUnformatted, _dart_cJSON_PrintUnformatted>( + 'cJSON_PrintUnformatted'); + +typedef _c_cJSON_PrintUnformatted = ffi.Pointer Function( + ffi.Pointer item, +); + +typedef _dart_cJSON_PrintUnformatted = ffi.Pointer Function( + ffi.Pointer item, +); + +ffi.Pointer cJSON_PrintBuffered( + ffi.Pointer item, + int prebuffer, + int fmt, +) { + return _cJSON_PrintBuffered( + item, + prebuffer, + fmt, + ); +} + +final _dart_cJSON_PrintBuffered _cJSON_PrintBuffered = + _dylib.lookupFunction<_c_cJSON_PrintBuffered, _dart_cJSON_PrintBuffered>( + 'cJSON_PrintBuffered'); + +typedef _c_cJSON_PrintBuffered = ffi.Pointer Function( + ffi.Pointer item, + ffi.Int32 prebuffer, + ffi.Int32 fmt, +); + +typedef _dart_cJSON_PrintBuffered = ffi.Pointer Function( + ffi.Pointer item, + int prebuffer, + int fmt, +); + +int cJSON_PrintPreallocated( + ffi.Pointer item, + ffi.Pointer buffer, + int length, + int format, +) { + return _cJSON_PrintPreallocated( + item, + buffer, + length, + format, + ); +} + +final _dart_cJSON_PrintPreallocated _cJSON_PrintPreallocated = _dylib + .lookupFunction<_c_cJSON_PrintPreallocated, _dart_cJSON_PrintPreallocated>( + 'cJSON_PrintPreallocated'); + +typedef _c_cJSON_PrintPreallocated = ffi.Int32 Function( + ffi.Pointer item, + ffi.Pointer buffer, + ffi.Int32 length, + ffi.Int32 format, +); + +typedef _dart_cJSON_PrintPreallocated = int Function( + ffi.Pointer item, + ffi.Pointer buffer, + int length, + int format, +); + +void cJSON_Delete( + ffi.Pointer item, +) { + return _cJSON_Delete( + item, + ); +} + +final _dart_cJSON_Delete _cJSON_Delete = + _dylib.lookupFunction<_c_cJSON_Delete, _dart_cJSON_Delete>('cJSON_Delete'); + +typedef _c_cJSON_Delete = ffi.Void Function( + ffi.Pointer item, +); + +typedef _dart_cJSON_Delete = void Function( + ffi.Pointer item, +); + +int cJSON_GetArraySize( + ffi.Pointer array, +) { + return _cJSON_GetArraySize( + array, + ); +} + +final _dart_cJSON_GetArraySize _cJSON_GetArraySize = + _dylib.lookupFunction<_c_cJSON_GetArraySize, _dart_cJSON_GetArraySize>( + 'cJSON_GetArraySize'); + +typedef _c_cJSON_GetArraySize = ffi.Int32 Function( + ffi.Pointer array, +); + +typedef _dart_cJSON_GetArraySize = int Function( + ffi.Pointer array, +); + +ffi.Pointer cJSON_GetArrayItem( + ffi.Pointer array, + int index, +) { + return _cJSON_GetArrayItem( + array, + index, + ); +} + +final _dart_cJSON_GetArrayItem _cJSON_GetArrayItem = + _dylib.lookupFunction<_c_cJSON_GetArrayItem, _dart_cJSON_GetArrayItem>( + 'cJSON_GetArrayItem'); + +typedef _c_cJSON_GetArrayItem = ffi.Pointer Function( + ffi.Pointer array, + ffi.Int32 index, +); + +typedef _dart_cJSON_GetArrayItem = ffi.Pointer Function( + ffi.Pointer array, + int index, +); + +ffi.Pointer cJSON_GetObjectItem( + ffi.Pointer object, + ffi.Pointer string, +) { + return _cJSON_GetObjectItem( + object, + string, + ); +} + +final _dart_cJSON_GetObjectItem _cJSON_GetObjectItem = + _dylib.lookupFunction<_c_cJSON_GetObjectItem, _dart_cJSON_GetObjectItem>( + 'cJSON_GetObjectItem'); + +typedef _c_cJSON_GetObjectItem = ffi.Pointer Function( + ffi.Pointer object, + ffi.Pointer string, +); + +typedef _dart_cJSON_GetObjectItem = ffi.Pointer Function( + ffi.Pointer object, + ffi.Pointer string, +); + +ffi.Pointer cJSON_GetObjectItemCaseSensitive( + ffi.Pointer object, + ffi.Pointer string, +) { + return _cJSON_GetObjectItemCaseSensitive( + object, + string, + ); +} + +final _dart_cJSON_GetObjectItemCaseSensitive _cJSON_GetObjectItemCaseSensitive = + _dylib.lookupFunction<_c_cJSON_GetObjectItemCaseSensitive, + _dart_cJSON_GetObjectItemCaseSensitive>( + 'cJSON_GetObjectItemCaseSensitive'); + +typedef _c_cJSON_GetObjectItemCaseSensitive = ffi.Pointer Function( + ffi.Pointer object, + ffi.Pointer string, +); + +typedef _dart_cJSON_GetObjectItemCaseSensitive = ffi.Pointer Function( + ffi.Pointer object, + ffi.Pointer string, +); + +int cJSON_HasObjectItem( + ffi.Pointer object, + ffi.Pointer string, +) { + return _cJSON_HasObjectItem( + object, + string, + ); +} + +final _dart_cJSON_HasObjectItem _cJSON_HasObjectItem = + _dylib.lookupFunction<_c_cJSON_HasObjectItem, _dart_cJSON_HasObjectItem>( + 'cJSON_HasObjectItem'); + +typedef _c_cJSON_HasObjectItem = ffi.Int32 Function( + ffi.Pointer object, + ffi.Pointer string, +); + +typedef _dart_cJSON_HasObjectItem = int Function( + ffi.Pointer object, + ffi.Pointer string, +); + +ffi.Pointer cJSON_GetErrorPtr() { + return _cJSON_GetErrorPtr(); +} + +final _dart_cJSON_GetErrorPtr _cJSON_GetErrorPtr = + _dylib.lookupFunction<_c_cJSON_GetErrorPtr, _dart_cJSON_GetErrorPtr>( + 'cJSON_GetErrorPtr'); + +typedef _c_cJSON_GetErrorPtr = ffi.Pointer Function(); + +typedef _dart_cJSON_GetErrorPtr = ffi.Pointer Function(); + +ffi.Pointer cJSON_GetStringValue( + ffi.Pointer item, +) { + return _cJSON_GetStringValue( + item, + ); +} + +final _dart_cJSON_GetStringValue _cJSON_GetStringValue = + _dylib.lookupFunction<_c_cJSON_GetStringValue, _dart_cJSON_GetStringValue>( + 'cJSON_GetStringValue'); + +typedef _c_cJSON_GetStringValue = ffi.Pointer Function( + ffi.Pointer item, +); + +typedef _dart_cJSON_GetStringValue = ffi.Pointer Function( + ffi.Pointer item, +); + +int cJSON_IsInvalid( + ffi.Pointer item, +) { + return _cJSON_IsInvalid( + item, + ); +} + +final _dart_cJSON_IsInvalid _cJSON_IsInvalid = + _dylib.lookupFunction<_c_cJSON_IsInvalid, _dart_cJSON_IsInvalid>( + 'cJSON_IsInvalid'); + +typedef _c_cJSON_IsInvalid = ffi.Int32 Function( + ffi.Pointer item, +); + +typedef _dart_cJSON_IsInvalid = int Function( + ffi.Pointer item, +); + +int cJSON_IsFalse( + ffi.Pointer item, +) { + return _cJSON_IsFalse( + item, + ); +} + +final _dart_cJSON_IsFalse _cJSON_IsFalse = _dylib + .lookupFunction<_c_cJSON_IsFalse, _dart_cJSON_IsFalse>('cJSON_IsFalse'); + +typedef _c_cJSON_IsFalse = ffi.Int32 Function( + ffi.Pointer item, +); + +typedef _dart_cJSON_IsFalse = int Function( + ffi.Pointer item, +); + +int cJSON_IsTrue( + ffi.Pointer item, +) { + return _cJSON_IsTrue( + item, + ); +} + +final _dart_cJSON_IsTrue _cJSON_IsTrue = + _dylib.lookupFunction<_c_cJSON_IsTrue, _dart_cJSON_IsTrue>('cJSON_IsTrue'); + +typedef _c_cJSON_IsTrue = ffi.Int32 Function( + ffi.Pointer item, +); + +typedef _dart_cJSON_IsTrue = int Function( + ffi.Pointer item, +); + +int cJSON_IsBool( + ffi.Pointer item, +) { + return _cJSON_IsBool( + item, + ); +} + +final _dart_cJSON_IsBool _cJSON_IsBool = + _dylib.lookupFunction<_c_cJSON_IsBool, _dart_cJSON_IsBool>('cJSON_IsBool'); + +typedef _c_cJSON_IsBool = ffi.Int32 Function( + ffi.Pointer item, +); + +typedef _dart_cJSON_IsBool = int Function( + ffi.Pointer item, +); + +int cJSON_IsNull( + ffi.Pointer item, +) { + return _cJSON_IsNull( + item, + ); +} + +final _dart_cJSON_IsNull _cJSON_IsNull = + _dylib.lookupFunction<_c_cJSON_IsNull, _dart_cJSON_IsNull>('cJSON_IsNull'); + +typedef _c_cJSON_IsNull = ffi.Int32 Function( + ffi.Pointer item, +); + +typedef _dart_cJSON_IsNull = int Function( + ffi.Pointer item, +); + +int cJSON_IsNumber( + ffi.Pointer item, +) { + return _cJSON_IsNumber( + item, + ); +} + +final _dart_cJSON_IsNumber _cJSON_IsNumber = _dylib + .lookupFunction<_c_cJSON_IsNumber, _dart_cJSON_IsNumber>('cJSON_IsNumber'); + +typedef _c_cJSON_IsNumber = ffi.Int32 Function( + ffi.Pointer item, +); + +typedef _dart_cJSON_IsNumber = int Function( + ffi.Pointer item, +); + +int cJSON_IsString( + ffi.Pointer item, +) { + return _cJSON_IsString( + item, + ); +} + +final _dart_cJSON_IsString _cJSON_IsString = _dylib + .lookupFunction<_c_cJSON_IsString, _dart_cJSON_IsString>('cJSON_IsString'); + +typedef _c_cJSON_IsString = ffi.Int32 Function( + ffi.Pointer item, +); + +typedef _dart_cJSON_IsString = int Function( + ffi.Pointer item, +); + +int cJSON_IsArray( + ffi.Pointer item, +) { + return _cJSON_IsArray( + item, + ); +} + +final _dart_cJSON_IsArray _cJSON_IsArray = _dylib + .lookupFunction<_c_cJSON_IsArray, _dart_cJSON_IsArray>('cJSON_IsArray'); + +typedef _c_cJSON_IsArray = ffi.Int32 Function( + ffi.Pointer item, +); + +typedef _dart_cJSON_IsArray = int Function( + ffi.Pointer item, +); + +int cJSON_IsObject( + ffi.Pointer item, +) { + return _cJSON_IsObject( + item, + ); +} + +final _dart_cJSON_IsObject _cJSON_IsObject = _dylib + .lookupFunction<_c_cJSON_IsObject, _dart_cJSON_IsObject>('cJSON_IsObject'); + +typedef _c_cJSON_IsObject = ffi.Int32 Function( + ffi.Pointer item, +); + +typedef _dart_cJSON_IsObject = int Function( + ffi.Pointer item, +); + +int cJSON_IsRaw( + ffi.Pointer item, +) { + return _cJSON_IsRaw( + item, + ); +} + +final _dart_cJSON_IsRaw _cJSON_IsRaw = + _dylib.lookupFunction<_c_cJSON_IsRaw, _dart_cJSON_IsRaw>('cJSON_IsRaw'); + +typedef _c_cJSON_IsRaw = ffi.Int32 Function( + ffi.Pointer item, +); + +typedef _dart_cJSON_IsRaw = int Function( + ffi.Pointer item, +); + +ffi.Pointer cJSON_CreateNull() { + return _cJSON_CreateNull(); +} + +final _dart_cJSON_CreateNull _cJSON_CreateNull = + _dylib.lookupFunction<_c_cJSON_CreateNull, _dart_cJSON_CreateNull>( + 'cJSON_CreateNull'); + +typedef _c_cJSON_CreateNull = ffi.Pointer Function(); + +typedef _dart_cJSON_CreateNull = ffi.Pointer Function(); + +ffi.Pointer cJSON_CreateTrue() { + return _cJSON_CreateTrue(); +} + +final _dart_cJSON_CreateTrue _cJSON_CreateTrue = + _dylib.lookupFunction<_c_cJSON_CreateTrue, _dart_cJSON_CreateTrue>( + 'cJSON_CreateTrue'); + +typedef _c_cJSON_CreateTrue = ffi.Pointer Function(); + +typedef _dart_cJSON_CreateTrue = ffi.Pointer Function(); + +ffi.Pointer cJSON_CreateFalse() { + return _cJSON_CreateFalse(); +} + +final _dart_cJSON_CreateFalse _cJSON_CreateFalse = + _dylib.lookupFunction<_c_cJSON_CreateFalse, _dart_cJSON_CreateFalse>( + 'cJSON_CreateFalse'); + +typedef _c_cJSON_CreateFalse = ffi.Pointer Function(); + +typedef _dart_cJSON_CreateFalse = ffi.Pointer Function(); + +ffi.Pointer cJSON_CreateBool( + int boolean, +) { + return _cJSON_CreateBool( + boolean, + ); +} + +final _dart_cJSON_CreateBool _cJSON_CreateBool = + _dylib.lookupFunction<_c_cJSON_CreateBool, _dart_cJSON_CreateBool>( + 'cJSON_CreateBool'); + +typedef _c_cJSON_CreateBool = ffi.Pointer Function( + ffi.Int32 boolean, +); + +typedef _dart_cJSON_CreateBool = ffi.Pointer Function( + int boolean, +); + +ffi.Pointer cJSON_CreateNumber( + double num, +) { + return _cJSON_CreateNumber( + num, + ); +} + +final _dart_cJSON_CreateNumber _cJSON_CreateNumber = + _dylib.lookupFunction<_c_cJSON_CreateNumber, _dart_cJSON_CreateNumber>( + 'cJSON_CreateNumber'); + +typedef _c_cJSON_CreateNumber = ffi.Pointer Function( + ffi.Double num, +); + +typedef _dart_cJSON_CreateNumber = ffi.Pointer Function( + double num, +); + +ffi.Pointer cJSON_CreateString( + ffi.Pointer string, +) { + return _cJSON_CreateString( + string, + ); +} + +final _dart_cJSON_CreateString _cJSON_CreateString = + _dylib.lookupFunction<_c_cJSON_CreateString, _dart_cJSON_CreateString>( + 'cJSON_CreateString'); + +typedef _c_cJSON_CreateString = ffi.Pointer Function( + ffi.Pointer string, +); + +typedef _dart_cJSON_CreateString = ffi.Pointer Function( + ffi.Pointer string, +); + +ffi.Pointer cJSON_CreateRaw( + ffi.Pointer raw, +) { + return _cJSON_CreateRaw( + raw, + ); +} + +final _dart_cJSON_CreateRaw _cJSON_CreateRaw = + _dylib.lookupFunction<_c_cJSON_CreateRaw, _dart_cJSON_CreateRaw>( + 'cJSON_CreateRaw'); + +typedef _c_cJSON_CreateRaw = ffi.Pointer Function( + ffi.Pointer raw, +); + +typedef _dart_cJSON_CreateRaw = ffi.Pointer Function( + ffi.Pointer raw, +); + +ffi.Pointer cJSON_CreateArray() { + return _cJSON_CreateArray(); +} + +final _dart_cJSON_CreateArray _cJSON_CreateArray = + _dylib.lookupFunction<_c_cJSON_CreateArray, _dart_cJSON_CreateArray>( + 'cJSON_CreateArray'); + +typedef _c_cJSON_CreateArray = ffi.Pointer Function(); + +typedef _dart_cJSON_CreateArray = ffi.Pointer Function(); + +ffi.Pointer cJSON_CreateObject() { + return _cJSON_CreateObject(); +} + +final _dart_cJSON_CreateObject _cJSON_CreateObject = + _dylib.lookupFunction<_c_cJSON_CreateObject, _dart_cJSON_CreateObject>( + 'cJSON_CreateObject'); + +typedef _c_cJSON_CreateObject = ffi.Pointer Function(); + +typedef _dart_cJSON_CreateObject = ffi.Pointer Function(); + +ffi.Pointer cJSON_CreateStringReference( + ffi.Pointer string, +) { + return _cJSON_CreateStringReference( + string, + ); +} + +final _dart_cJSON_CreateStringReference _cJSON_CreateStringReference = + _dylib.lookupFunction<_c_cJSON_CreateStringReference, + _dart_cJSON_CreateStringReference>('cJSON_CreateStringReference'); + +typedef _c_cJSON_CreateStringReference = ffi.Pointer Function( + ffi.Pointer string, +); + +typedef _dart_cJSON_CreateStringReference = ffi.Pointer Function( + ffi.Pointer string, +); + +ffi.Pointer cJSON_CreateObjectReference( + ffi.Pointer child, +) { + return _cJSON_CreateObjectReference( + child, + ); +} + +final _dart_cJSON_CreateObjectReference _cJSON_CreateObjectReference = + _dylib.lookupFunction<_c_cJSON_CreateObjectReference, + _dart_cJSON_CreateObjectReference>('cJSON_CreateObjectReference'); + +typedef _c_cJSON_CreateObjectReference = ffi.Pointer Function( + ffi.Pointer child, +); + +typedef _dart_cJSON_CreateObjectReference = ffi.Pointer Function( + ffi.Pointer child, +); + +ffi.Pointer cJSON_CreateArrayReference( + ffi.Pointer child, +) { + return _cJSON_CreateArrayReference( + child, + ); +} + +final _dart_cJSON_CreateArrayReference _cJSON_CreateArrayReference = + _dylib.lookupFunction<_c_cJSON_CreateArrayReference, + _dart_cJSON_CreateArrayReference>('cJSON_CreateArrayReference'); + +typedef _c_cJSON_CreateArrayReference = ffi.Pointer Function( + ffi.Pointer child, +); + +typedef _dart_cJSON_CreateArrayReference = ffi.Pointer Function( + ffi.Pointer child, +); + +ffi.Pointer cJSON_CreateIntArray( + ffi.Pointer numbers, + int count, +) { + return _cJSON_CreateIntArray( + numbers, + count, + ); +} + +final _dart_cJSON_CreateIntArray _cJSON_CreateIntArray = + _dylib.lookupFunction<_c_cJSON_CreateIntArray, _dart_cJSON_CreateIntArray>( + 'cJSON_CreateIntArray'); + +typedef _c_cJSON_CreateIntArray = ffi.Pointer Function( + ffi.Pointer numbers, + ffi.Int32 count, +); + +typedef _dart_cJSON_CreateIntArray = ffi.Pointer Function( + ffi.Pointer numbers, + int count, +); + +ffi.Pointer cJSON_CreateFloatArray( + ffi.Pointer numbers, + int count, +) { + return _cJSON_CreateFloatArray( + numbers, + count, + ); +} + +final _dart_cJSON_CreateFloatArray _cJSON_CreateFloatArray = _dylib + .lookupFunction<_c_cJSON_CreateFloatArray, _dart_cJSON_CreateFloatArray>( + 'cJSON_CreateFloatArray'); + +typedef _c_cJSON_CreateFloatArray = ffi.Pointer Function( + ffi.Pointer numbers, + ffi.Int32 count, +); + +typedef _dart_cJSON_CreateFloatArray = ffi.Pointer Function( + ffi.Pointer numbers, + int count, +); + +ffi.Pointer cJSON_CreateDoubleArray( + ffi.Pointer numbers, + int count, +) { + return _cJSON_CreateDoubleArray( + numbers, + count, + ); +} + +final _dart_cJSON_CreateDoubleArray _cJSON_CreateDoubleArray = _dylib + .lookupFunction<_c_cJSON_CreateDoubleArray, _dart_cJSON_CreateDoubleArray>( + 'cJSON_CreateDoubleArray'); + +typedef _c_cJSON_CreateDoubleArray = ffi.Pointer Function( + ffi.Pointer numbers, + ffi.Int32 count, +); + +typedef _dart_cJSON_CreateDoubleArray = ffi.Pointer Function( + ffi.Pointer numbers, + int count, +); + +ffi.Pointer cJSON_CreateStringArray( + ffi.Pointer> strings, + int count, +) { + return _cJSON_CreateStringArray( + strings, + count, + ); +} + +final _dart_cJSON_CreateStringArray _cJSON_CreateStringArray = _dylib + .lookupFunction<_c_cJSON_CreateStringArray, _dart_cJSON_CreateStringArray>( + 'cJSON_CreateStringArray'); + +typedef _c_cJSON_CreateStringArray = ffi.Pointer Function( + ffi.Pointer> strings, + ffi.Int32 count, +); + +typedef _dart_cJSON_CreateStringArray = ffi.Pointer Function( + ffi.Pointer> strings, + int count, +); + +void cJSON_AddItemToArray( + ffi.Pointer array, + ffi.Pointer item, +) { + return _cJSON_AddItemToArray( + array, + item, + ); +} + +final _dart_cJSON_AddItemToArray _cJSON_AddItemToArray = + _dylib.lookupFunction<_c_cJSON_AddItemToArray, _dart_cJSON_AddItemToArray>( + 'cJSON_AddItemToArray'); + +typedef _c_cJSON_AddItemToArray = ffi.Void Function( + ffi.Pointer array, + ffi.Pointer item, +); + +typedef _dart_cJSON_AddItemToArray = void Function( + ffi.Pointer array, + ffi.Pointer item, +); + +void cJSON_AddItemToObject( + ffi.Pointer object, + ffi.Pointer string, + ffi.Pointer item, +) { + return _cJSON_AddItemToObject( + object, + string, + item, + ); +} + +final _dart_cJSON_AddItemToObject _cJSON_AddItemToObject = _dylib + .lookupFunction<_c_cJSON_AddItemToObject, _dart_cJSON_AddItemToObject>( + 'cJSON_AddItemToObject'); + +typedef _c_cJSON_AddItemToObject = ffi.Void Function( + ffi.Pointer object, + ffi.Pointer string, + ffi.Pointer item, +); + +typedef _dart_cJSON_AddItemToObject = void Function( + ffi.Pointer object, + ffi.Pointer string, + ffi.Pointer item, +); + +void cJSON_AddItemToObjectCS( + ffi.Pointer object, + ffi.Pointer string, + ffi.Pointer item, +) { + return _cJSON_AddItemToObjectCS( + object, + string, + item, + ); +} + +final _dart_cJSON_AddItemToObjectCS _cJSON_AddItemToObjectCS = _dylib + .lookupFunction<_c_cJSON_AddItemToObjectCS, _dart_cJSON_AddItemToObjectCS>( + 'cJSON_AddItemToObjectCS'); + +typedef _c_cJSON_AddItemToObjectCS = ffi.Void Function( + ffi.Pointer object, + ffi.Pointer string, + ffi.Pointer item, +); + +typedef _dart_cJSON_AddItemToObjectCS = void Function( + ffi.Pointer object, + ffi.Pointer string, + ffi.Pointer item, +); + +void cJSON_AddItemReferenceToArray( + ffi.Pointer array, + ffi.Pointer item, +) { + return _cJSON_AddItemReferenceToArray( + array, + item, + ); +} + +final _dart_cJSON_AddItemReferenceToArray _cJSON_AddItemReferenceToArray = + _dylib.lookupFunction<_c_cJSON_AddItemReferenceToArray, + _dart_cJSON_AddItemReferenceToArray>('cJSON_AddItemReferenceToArray'); + +typedef _c_cJSON_AddItemReferenceToArray = ffi.Void Function( + ffi.Pointer array, + ffi.Pointer item, +); + +typedef _dart_cJSON_AddItemReferenceToArray = void Function( + ffi.Pointer array, + ffi.Pointer item, +); + +void cJSON_AddItemReferenceToObject( + ffi.Pointer object, + ffi.Pointer string, + ffi.Pointer item, +) { + return _cJSON_AddItemReferenceToObject( + object, + string, + item, + ); +} + +final _dart_cJSON_AddItemReferenceToObject _cJSON_AddItemReferenceToObject = + _dylib.lookupFunction<_c_cJSON_AddItemReferenceToObject, + _dart_cJSON_AddItemReferenceToObject>('cJSON_AddItemReferenceToObject'); + +typedef _c_cJSON_AddItemReferenceToObject = ffi.Void Function( + ffi.Pointer object, + ffi.Pointer string, + ffi.Pointer item, +); + +typedef _dart_cJSON_AddItemReferenceToObject = void Function( + ffi.Pointer object, + ffi.Pointer string, + ffi.Pointer item, +); + +ffi.Pointer cJSON_DetachItemViaPointer( + ffi.Pointer parent, + ffi.Pointer item, +) { + return _cJSON_DetachItemViaPointer( + parent, + item, + ); +} + +final _dart_cJSON_DetachItemViaPointer _cJSON_DetachItemViaPointer = + _dylib.lookupFunction<_c_cJSON_DetachItemViaPointer, + _dart_cJSON_DetachItemViaPointer>('cJSON_DetachItemViaPointer'); + +typedef _c_cJSON_DetachItemViaPointer = ffi.Pointer Function( + ffi.Pointer parent, + ffi.Pointer item, +); + +typedef _dart_cJSON_DetachItemViaPointer = ffi.Pointer Function( + ffi.Pointer parent, + ffi.Pointer item, +); + +ffi.Pointer cJSON_DetachItemFromArray( + ffi.Pointer array, + int which, +) { + return _cJSON_DetachItemFromArray( + array, + which, + ); +} + +final _dart_cJSON_DetachItemFromArray _cJSON_DetachItemFromArray = + _dylib.lookupFunction<_c_cJSON_DetachItemFromArray, + _dart_cJSON_DetachItemFromArray>('cJSON_DetachItemFromArray'); + +typedef _c_cJSON_DetachItemFromArray = ffi.Pointer Function( + ffi.Pointer array, + ffi.Int32 which, +); + +typedef _dart_cJSON_DetachItemFromArray = ffi.Pointer Function( + ffi.Pointer array, + int which, +); + +void cJSON_DeleteItemFromArray( + ffi.Pointer array, + int which, +) { + return _cJSON_DeleteItemFromArray( + array, + which, + ); +} + +final _dart_cJSON_DeleteItemFromArray _cJSON_DeleteItemFromArray = + _dylib.lookupFunction<_c_cJSON_DeleteItemFromArray, + _dart_cJSON_DeleteItemFromArray>('cJSON_DeleteItemFromArray'); + +typedef _c_cJSON_DeleteItemFromArray = ffi.Void Function( + ffi.Pointer array, + ffi.Int32 which, +); + +typedef _dart_cJSON_DeleteItemFromArray = void Function( + ffi.Pointer array, + int which, +); + +ffi.Pointer cJSON_DetachItemFromObject( + ffi.Pointer object, + ffi.Pointer string, +) { + return _cJSON_DetachItemFromObject( + object, + string, + ); +} + +final _dart_cJSON_DetachItemFromObject _cJSON_DetachItemFromObject = + _dylib.lookupFunction<_c_cJSON_DetachItemFromObject, + _dart_cJSON_DetachItemFromObject>('cJSON_DetachItemFromObject'); + +typedef _c_cJSON_DetachItemFromObject = ffi.Pointer Function( + ffi.Pointer object, + ffi.Pointer string, +); + +typedef _dart_cJSON_DetachItemFromObject = ffi.Pointer Function( + ffi.Pointer object, + ffi.Pointer string, +); + +ffi.Pointer cJSON_DetachItemFromObjectCaseSensitive( + ffi.Pointer object, + ffi.Pointer string, +) { + return _cJSON_DetachItemFromObjectCaseSensitive( + object, + string, + ); +} + +final _dart_cJSON_DetachItemFromObjectCaseSensitive + _cJSON_DetachItemFromObjectCaseSensitive = _dylib.lookupFunction< + _c_cJSON_DetachItemFromObjectCaseSensitive, + _dart_cJSON_DetachItemFromObjectCaseSensitive>( + 'cJSON_DetachItemFromObjectCaseSensitive'); + +typedef _c_cJSON_DetachItemFromObjectCaseSensitive = ffi.Pointer + Function( + ffi.Pointer object, + ffi.Pointer string, +); + +typedef _dart_cJSON_DetachItemFromObjectCaseSensitive = ffi.Pointer + Function( + ffi.Pointer object, + ffi.Pointer string, +); + +void cJSON_DeleteItemFromObject( + ffi.Pointer object, + ffi.Pointer string, +) { + return _cJSON_DeleteItemFromObject( + object, + string, + ); +} + +final _dart_cJSON_DeleteItemFromObject _cJSON_DeleteItemFromObject = + _dylib.lookupFunction<_c_cJSON_DeleteItemFromObject, + _dart_cJSON_DeleteItemFromObject>('cJSON_DeleteItemFromObject'); + +typedef _c_cJSON_DeleteItemFromObject = ffi.Void Function( + ffi.Pointer object, + ffi.Pointer string, +); + +typedef _dart_cJSON_DeleteItemFromObject = void Function( + ffi.Pointer object, + ffi.Pointer string, +); + +void cJSON_DeleteItemFromObjectCaseSensitive( + ffi.Pointer object, + ffi.Pointer string, +) { + return _cJSON_DeleteItemFromObjectCaseSensitive( + object, + string, + ); +} + +final _dart_cJSON_DeleteItemFromObjectCaseSensitive + _cJSON_DeleteItemFromObjectCaseSensitive = _dylib.lookupFunction< + _c_cJSON_DeleteItemFromObjectCaseSensitive, + _dart_cJSON_DeleteItemFromObjectCaseSensitive>( + 'cJSON_DeleteItemFromObjectCaseSensitive'); + +typedef _c_cJSON_DeleteItemFromObjectCaseSensitive = ffi.Void Function( + ffi.Pointer object, + ffi.Pointer string, +); + +typedef _dart_cJSON_DeleteItemFromObjectCaseSensitive = void Function( + ffi.Pointer object, + ffi.Pointer string, +); + +void cJSON_InsertItemInArray( + ffi.Pointer array, + int which, + ffi.Pointer newitem, +) { + return _cJSON_InsertItemInArray( + array, + which, + newitem, + ); +} + +final _dart_cJSON_InsertItemInArray _cJSON_InsertItemInArray = _dylib + .lookupFunction<_c_cJSON_InsertItemInArray, _dart_cJSON_InsertItemInArray>( + 'cJSON_InsertItemInArray'); + +typedef _c_cJSON_InsertItemInArray = ffi.Void Function( + ffi.Pointer array, + ffi.Int32 which, + ffi.Pointer newitem, +); + +typedef _dart_cJSON_InsertItemInArray = void Function( + ffi.Pointer array, + int which, + ffi.Pointer newitem, +); + +int cJSON_ReplaceItemViaPointer( + ffi.Pointer parent, + ffi.Pointer item, + ffi.Pointer replacement, +) { + return _cJSON_ReplaceItemViaPointer( + parent, + item, + replacement, + ); +} + +final _dart_cJSON_ReplaceItemViaPointer _cJSON_ReplaceItemViaPointer = + _dylib.lookupFunction<_c_cJSON_ReplaceItemViaPointer, + _dart_cJSON_ReplaceItemViaPointer>('cJSON_ReplaceItemViaPointer'); + +typedef _c_cJSON_ReplaceItemViaPointer = ffi.Int32 Function( + ffi.Pointer parent, + ffi.Pointer item, + ffi.Pointer replacement, +); + +typedef _dart_cJSON_ReplaceItemViaPointer = int Function( + ffi.Pointer parent, + ffi.Pointer item, + ffi.Pointer replacement, +); + +void cJSON_ReplaceItemInArray( + ffi.Pointer array, + int which, + ffi.Pointer newitem, +) { + return _cJSON_ReplaceItemInArray( + array, + which, + newitem, + ); +} + +final _dart_cJSON_ReplaceItemInArray _cJSON_ReplaceItemInArray = + _dylib.lookupFunction<_c_cJSON_ReplaceItemInArray, + _dart_cJSON_ReplaceItemInArray>('cJSON_ReplaceItemInArray'); + +typedef _c_cJSON_ReplaceItemInArray = ffi.Void Function( + ffi.Pointer array, + ffi.Int32 which, + ffi.Pointer newitem, +); + +typedef _dart_cJSON_ReplaceItemInArray = void Function( + ffi.Pointer array, + int which, + ffi.Pointer newitem, +); + +void cJSON_ReplaceItemInObject( + ffi.Pointer object, + ffi.Pointer string, + ffi.Pointer newitem, +) { + return _cJSON_ReplaceItemInObject( + object, + string, + newitem, + ); +} + +final _dart_cJSON_ReplaceItemInObject _cJSON_ReplaceItemInObject = + _dylib.lookupFunction<_c_cJSON_ReplaceItemInObject, + _dart_cJSON_ReplaceItemInObject>('cJSON_ReplaceItemInObject'); + +typedef _c_cJSON_ReplaceItemInObject = ffi.Void Function( + ffi.Pointer object, + ffi.Pointer string, + ffi.Pointer newitem, +); + +typedef _dart_cJSON_ReplaceItemInObject = void Function( + ffi.Pointer object, + ffi.Pointer string, + ffi.Pointer newitem, +); + +void cJSON_ReplaceItemInObjectCaseSensitive( + ffi.Pointer object, + ffi.Pointer string, + ffi.Pointer newitem, +) { + return _cJSON_ReplaceItemInObjectCaseSensitive( + object, + string, + newitem, + ); +} + +final _dart_cJSON_ReplaceItemInObjectCaseSensitive + _cJSON_ReplaceItemInObjectCaseSensitive = _dylib.lookupFunction< + _c_cJSON_ReplaceItemInObjectCaseSensitive, + _dart_cJSON_ReplaceItemInObjectCaseSensitive>( + 'cJSON_ReplaceItemInObjectCaseSensitive'); + +typedef _c_cJSON_ReplaceItemInObjectCaseSensitive = ffi.Void Function( + ffi.Pointer object, + ffi.Pointer string, + ffi.Pointer newitem, +); + +typedef _dart_cJSON_ReplaceItemInObjectCaseSensitive = void Function( + ffi.Pointer object, + ffi.Pointer string, + ffi.Pointer newitem, +); + +ffi.Pointer cJSON_Duplicate( + ffi.Pointer item, + int recurse, +) { + return _cJSON_Duplicate( + item, + recurse, + ); +} + +final _dart_cJSON_Duplicate _cJSON_Duplicate = + _dylib.lookupFunction<_c_cJSON_Duplicate, _dart_cJSON_Duplicate>( + 'cJSON_Duplicate'); + +typedef _c_cJSON_Duplicate = ffi.Pointer Function( + ffi.Pointer item, + ffi.Int32 recurse, +); + +typedef _dart_cJSON_Duplicate = ffi.Pointer Function( + ffi.Pointer item, + int recurse, +); + +int cJSON_Compare( + ffi.Pointer a, + ffi.Pointer b, + int case_sensitive, +) { + return _cJSON_Compare( + a, + b, + case_sensitive, + ); +} + +final _dart_cJSON_Compare _cJSON_Compare = _dylib + .lookupFunction<_c_cJSON_Compare, _dart_cJSON_Compare>('cJSON_Compare'); + +typedef _c_cJSON_Compare = ffi.Int32 Function( + ffi.Pointer a, + ffi.Pointer b, + ffi.Int32 case_sensitive, +); + +typedef _dart_cJSON_Compare = int Function( + ffi.Pointer a, + ffi.Pointer b, + int case_sensitive, +); + +void cJSON_Minify( + ffi.Pointer json, +) { + return _cJSON_Minify( + json, + ); +} + +final _dart_cJSON_Minify _cJSON_Minify = + _dylib.lookupFunction<_c_cJSON_Minify, _dart_cJSON_Minify>('cJSON_Minify'); + +typedef _c_cJSON_Minify = ffi.Void Function( + ffi.Pointer json, +); + +typedef _dart_cJSON_Minify = void Function( + ffi.Pointer json, +); + +ffi.Pointer cJSON_AddNullToObject( + ffi.Pointer object, + ffi.Pointer name, +) { + return _cJSON_AddNullToObject( + object, + name, + ); +} + +final _dart_cJSON_AddNullToObject _cJSON_AddNullToObject = _dylib + .lookupFunction<_c_cJSON_AddNullToObject, _dart_cJSON_AddNullToObject>( + 'cJSON_AddNullToObject'); + +typedef _c_cJSON_AddNullToObject = ffi.Pointer Function( + ffi.Pointer object, + ffi.Pointer name, +); + +typedef _dart_cJSON_AddNullToObject = ffi.Pointer Function( + ffi.Pointer object, + ffi.Pointer name, +); + +ffi.Pointer cJSON_AddTrueToObject( + ffi.Pointer object, + ffi.Pointer name, +) { + return _cJSON_AddTrueToObject( + object, + name, + ); +} + +final _dart_cJSON_AddTrueToObject _cJSON_AddTrueToObject = _dylib + .lookupFunction<_c_cJSON_AddTrueToObject, _dart_cJSON_AddTrueToObject>( + 'cJSON_AddTrueToObject'); + +typedef _c_cJSON_AddTrueToObject = ffi.Pointer Function( + ffi.Pointer object, + ffi.Pointer name, +); + +typedef _dart_cJSON_AddTrueToObject = ffi.Pointer Function( + ffi.Pointer object, + ffi.Pointer name, +); + +ffi.Pointer cJSON_AddFalseToObject( + ffi.Pointer object, + ffi.Pointer name, +) { + return _cJSON_AddFalseToObject( + object, + name, + ); +} + +final _dart_cJSON_AddFalseToObject _cJSON_AddFalseToObject = _dylib + .lookupFunction<_c_cJSON_AddFalseToObject, _dart_cJSON_AddFalseToObject>( + 'cJSON_AddFalseToObject'); + +typedef _c_cJSON_AddFalseToObject = ffi.Pointer Function( + ffi.Pointer object, + ffi.Pointer name, +); + +typedef _dart_cJSON_AddFalseToObject = ffi.Pointer Function( + ffi.Pointer object, + ffi.Pointer name, +); + +ffi.Pointer cJSON_AddBoolToObject( + ffi.Pointer object, + ffi.Pointer name, + int boolean, +) { + return _cJSON_AddBoolToObject( + object, + name, + boolean, + ); +} + +final _dart_cJSON_AddBoolToObject _cJSON_AddBoolToObject = _dylib + .lookupFunction<_c_cJSON_AddBoolToObject, _dart_cJSON_AddBoolToObject>( + 'cJSON_AddBoolToObject'); + +typedef _c_cJSON_AddBoolToObject = ffi.Pointer Function( + ffi.Pointer object, + ffi.Pointer name, + ffi.Int32 boolean, +); + +typedef _dart_cJSON_AddBoolToObject = ffi.Pointer Function( + ffi.Pointer object, + ffi.Pointer name, + int boolean, +); + +ffi.Pointer cJSON_AddNumberToObject( + ffi.Pointer object, + ffi.Pointer name, + double number, +) { + return _cJSON_AddNumberToObject( + object, + name, + number, + ); +} + +final _dart_cJSON_AddNumberToObject _cJSON_AddNumberToObject = _dylib + .lookupFunction<_c_cJSON_AddNumberToObject, _dart_cJSON_AddNumberToObject>( + 'cJSON_AddNumberToObject'); + +typedef _c_cJSON_AddNumberToObject = ffi.Pointer Function( + ffi.Pointer object, + ffi.Pointer name, + ffi.Double number, +); + +typedef _dart_cJSON_AddNumberToObject = ffi.Pointer Function( + ffi.Pointer object, + ffi.Pointer name, + double number, +); + +ffi.Pointer cJSON_AddStringToObject( + ffi.Pointer object, + ffi.Pointer name, + ffi.Pointer string, +) { + return _cJSON_AddStringToObject( + object, + name, + string, + ); +} + +final _dart_cJSON_AddStringToObject _cJSON_AddStringToObject = _dylib + .lookupFunction<_c_cJSON_AddStringToObject, _dart_cJSON_AddStringToObject>( + 'cJSON_AddStringToObject'); + +typedef _c_cJSON_AddStringToObject = ffi.Pointer Function( + ffi.Pointer object, + ffi.Pointer name, + ffi.Pointer string, +); + +typedef _dart_cJSON_AddStringToObject = ffi.Pointer Function( + ffi.Pointer object, + ffi.Pointer name, + ffi.Pointer string, +); + +ffi.Pointer cJSON_AddRawToObject( + ffi.Pointer object, + ffi.Pointer name, + ffi.Pointer raw, +) { + return _cJSON_AddRawToObject( + object, + name, + raw, + ); +} + +final _dart_cJSON_AddRawToObject _cJSON_AddRawToObject = + _dylib.lookupFunction<_c_cJSON_AddRawToObject, _dart_cJSON_AddRawToObject>( + 'cJSON_AddRawToObject'); + +typedef _c_cJSON_AddRawToObject = ffi.Pointer Function( + ffi.Pointer object, + ffi.Pointer name, + ffi.Pointer raw, +); + +typedef _dart_cJSON_AddRawToObject = ffi.Pointer Function( + ffi.Pointer object, + ffi.Pointer name, + ffi.Pointer raw, +); + +ffi.Pointer cJSON_AddObjectToObject( + ffi.Pointer object, + ffi.Pointer name, +) { + return _cJSON_AddObjectToObject( + object, + name, + ); +} + +final _dart_cJSON_AddObjectToObject _cJSON_AddObjectToObject = _dylib + .lookupFunction<_c_cJSON_AddObjectToObject, _dart_cJSON_AddObjectToObject>( + 'cJSON_AddObjectToObject'); + +typedef _c_cJSON_AddObjectToObject = ffi.Pointer Function( + ffi.Pointer object, + ffi.Pointer name, +); + +typedef _dart_cJSON_AddObjectToObject = ffi.Pointer Function( + ffi.Pointer object, + ffi.Pointer name, +); + +ffi.Pointer cJSON_AddArrayToObject( + ffi.Pointer object, + ffi.Pointer name, +) { + return _cJSON_AddArrayToObject( + object, + name, + ); +} + +final _dart_cJSON_AddArrayToObject _cJSON_AddArrayToObject = _dylib + .lookupFunction<_c_cJSON_AddArrayToObject, _dart_cJSON_AddArrayToObject>( + 'cJSON_AddArrayToObject'); + +typedef _c_cJSON_AddArrayToObject = ffi.Pointer Function( + ffi.Pointer object, + ffi.Pointer name, +); + +typedef _dart_cJSON_AddArrayToObject = ffi.Pointer Function( + ffi.Pointer object, + ffi.Pointer name, +); + +double cJSON_SetNumberHelper( + ffi.Pointer object, + double number, +) { + return _cJSON_SetNumberHelper( + object, + number, + ); +} + +final _dart_cJSON_SetNumberHelper _cJSON_SetNumberHelper = _dylib + .lookupFunction<_c_cJSON_SetNumberHelper, _dart_cJSON_SetNumberHelper>( + 'cJSON_SetNumberHelper'); + +typedef _c_cJSON_SetNumberHelper = ffi.Double Function( + ffi.Pointer object, + ffi.Double number, +); + +typedef _dart_cJSON_SetNumberHelper = double Function( + ffi.Pointer object, + double number, +); + +ffi.Pointer cJSON_malloc( + int size, +) { + return _cJSON_malloc( + size, + ); +} + +final _dart_cJSON_malloc _cJSON_malloc = + _dylib.lookupFunction<_c_cJSON_malloc, _dart_cJSON_malloc>('cJSON_malloc'); + +typedef _c_cJSON_malloc = ffi.Pointer Function( + ffi.Uint64 size, +); + +typedef _dart_cJSON_malloc = ffi.Pointer Function( + int size, +); + +void cJSON_free( + ffi.Pointer object, +) { + return _cJSON_free( + object, + ); +} + +final _dart_cJSON_free _cJSON_free = + _dylib.lookupFunction<_c_cJSON_free, _dart_cJSON_free>('cJSON_free'); + +typedef _c_cJSON_free = ffi.Void Function( + ffi.Pointer object, +); + +typedef _dart_cJSON_free = void Function( + ffi.Pointer object, +); diff --git a/example/c_json/example.json b/example/c_json/example.json new file mode 100644 index 00000000..073b05cb --- /dev/null +++ b/example/c_json/example.json @@ -0,0 +1,14 @@ +{ + "name": "CoolGuy", + "age": 21, + "nicknames": [ + { + "name": "Mr. Cool", + "length": 8 + }, + { + "name": "Ice Cold", + "length": 8 + } + ] +} diff --git a/example/c_json/main.dart b/example/c_json/main.dart new file mode 100644 index 00000000..22db1835 --- /dev/null +++ b/example/c_json/main.dart @@ -0,0 +1,98 @@ +// Copyright (c) 2020, the Dart project authors. Please see the AUTHORS file +// for details. All rights reserved. Use of this source code is governed by a +// BSD-style license that can be found in the LICENSE file. + +import 'dart:convert'; +import 'dart:ffi'; +import 'dart:io'; + +import 'package:ffi/ffi.dart'; + +import 'cjson_generated_bindings.dart' as cjson; + +/// Using the generated C_JSON bindings. +void main() { + // Initialise cjson bindings. + cjson.init(DynamicLibrary.open(_getPath())); + + // Load json from [example.json] file. + final jsonString = File('./example.json').readAsStringSync(); + + // Parse this json string using our cJSON library. + final cjsonParsedJson = cjson.cJSON_Parse(Utf8.toUtf8(jsonString).cast()); + if (cjsonParsedJson == nullptr) { + print('Error parsing cjson.'); + exit(1); + } + // The json is now stored in some C data structure which we need + // to iterate and convert to a dart object (map/list). + + // Converting cjson object to a dart object. + final dynamic dartJson = convertCJsonToDartObj(cjsonParsedJson.cast()); + + // Delete the cjsonParsedJson object. + cjson.cJSON_Delete(cjsonParsedJson); + + // Check if the converted json is correct + // by comparing the result with json converted by `dart:convert`. + if (dartJson.toString() == json.decode(jsonString).toString()) { + print('Parsed Json: $dartJson'); + print('Json converted successfully'); + } else { + print("Converted json doesn't match\n"); + print('Actual:\n' + dartJson.toString() + '\n'); + print('Expected:\n' + json.decode(jsonString).toString()); + } +} + +String _getPath() { + var path = '../../third_party/cjson_library/libcjson.so'; + if (Platform.isMacOS) { + path = '../../third_party/cjson_library/libstructs.dylib'; + } + if (Platform.isWindows) { + path = r'..\..\third_party\cjson_library\Debug\structs.dll'; + } + return path; +} + +dynamic convertCJsonToDartObj(Pointer parsedcjson) { + dynamic obj; + if (cjson.cJSON_IsObject(parsedcjson.cast()) == 1) { + obj = {}; + + Pointer ptr; + ptr = parsedcjson.ref.child; + while (ptr != nullptr) { + final dynamic o = convertCJsonToDartObj(ptr); + _addToObj(obj, o, ptr.ref.string.cast()); + ptr = ptr.ref.next; + } + } else if (cjson.cJSON_IsArray(parsedcjson.cast()) == 1) { + obj = []; + + Pointer ptr; + ptr = parsedcjson.ref.child; + while (ptr != nullptr) { + final dynamic o = convertCJsonToDartObj(ptr); + _addToObj(obj, o); + ptr = ptr.ref.next; + } + } else if (cjson.cJSON_IsString(parsedcjson.cast()) == 1) { + obj = Utf8.fromUtf8(parsedcjson.ref.valuestring.cast()); + } else if (cjson.cJSON_IsNumber(parsedcjson.cast()) == 1) { + obj = parsedcjson.ref.valueint == parsedcjson.ref.valuedouble + ? parsedcjson.ref.valueint + : parsedcjson.ref.valuedouble; + } + + return obj; +} + +void _addToObj(dynamic obj, dynamic o, [Pointer name]) { + if (obj is Map) { + obj[Utf8.fromUtf8(name)] = o; + } else if (obj is List) { + obj.add(o); + } +} diff --git a/example/c_json/pubspec.yaml b/example/c_json/pubspec.yaml new file mode 100644 index 00000000..7e913b6e --- /dev/null +++ b/example/c_json/pubspec.yaml @@ -0,0 +1,23 @@ +# Copyright (c) 2020, the Dart project authors. Please see the AUTHORS file +# for details. All rights reserved. Use of this source code is governed by a +# BSD-style license that can be found in the LICENSE file. + +name: c_json_example + +environment: + sdk: '>=2.8.1 <3.0.0' + +dependencies: + ffi: ^0.1.3 + +dev_dependencies: + ffigen: + path: '../../' + +ffigen: + output: 'cjson_generated_bindings.dart' + headers: + - '../../third_party/cjson_library/cJSON.h' + header-filter: + include: + - 'cJSON.h' diff --git a/example/libclang-example/.gitignore b/example/libclang-example/.gitignore new file mode 100644 index 00000000..1b051642 --- /dev/null +++ b/example/libclang-example/.gitignore @@ -0,0 +1,11 @@ +# Files and directories created by pub. +.dart_tool/ +.packages +# Remove the following pattern if you wish to check in your lock file. +pubspec.lock + +# Conventional directory for build outputs. +build/ + +# Directory created by dartdoc. +doc/api/ diff --git a/example/libclang-example/generated_bindings.dart b/example/libclang-example/generated_bindings.dart new file mode 100644 index 00000000..f68f6323 --- /dev/null +++ b/example/libclang-example/generated_bindings.dart @@ -0,0 +1,4405 @@ +/// AUTO GENERATED FILE, DO NOT EDIT. +/// +/// Generated by `package:ffigen`. +import 'dart:ffi' as ffi; + +/// Holds the Dynamic library. +ffi.DynamicLibrary _dylib; + +/// Initialises the Dynamic library. +void init(ffi.DynamicLibrary dylib) { + _dylib = dylib; +} + +/// Contains the results of code-completion. +class CXCodeCompleteResults extends ffi.Struct { + ffi.Pointer Results; + + @ffi.Uint32() + int NumResults; +} + +/// A single result of code completion. +class CXCompletionResult extends ffi.Struct { + @ffi.Int32() + int CursorKind; + + ffi.Pointer CompletionString; +} + +/// A cursor representing some element in the abstract syntax tree for a translation unit. +class CXCursor extends ffi.Struct { + @ffi.Int32() + int kind; + + @ffi.Int32() + int xdata; + + ffi.Pointer _data_item_0; + ffi.Pointer _data_item_1; + ffi.Pointer _data_item_2; + + /// helper for array, supports `[]` operator + _ArrayHelper_CXCursor_data get data => _ArrayHelper_CXCursor_data(this, 3); +} + +/// Helper for array data in struct CXCursor +class _ArrayHelper_CXCursor_data { + final CXCursor _struct; + final int length; + _ArrayHelper_CXCursor_data(this._struct, this.length); + void operator []=(int index, ffi.Pointer value) { + switch (index) { + case 0: + _struct._data_item_0 = value; + break; + case 1: + _struct._data_item_1 = value; + break; + case 2: + _struct._data_item_2 = value; + break; + default: + throw RangeError('Index $index must be in the range [0..2].'); + } + } + + ffi.Pointer operator [](int index) { + switch (index) { + case 0: + return _struct._data_item_0; + case 1: + return _struct._data_item_1; + case 2: + return _struct._data_item_2; + default: + throw RangeError('Index $index must be in the range [0..2].'); + } + } + + @override + String toString() { + if (length == 0) return '[]'; + final sb = StringBuffer('['); + sb.write(this[0]); + for (var i = 1; i < length; i++) { + sb.write(','); + sb.write(this[i]); + } + sb.write(']'); + return sb.toString(); + } +} + +class CXCursorAndRangeVisitor extends ffi.Struct { + ffi.Pointer context; + + ffi.Pointer> visit; +} + +class CXCursorSetImpl extends ffi.Struct {} + +typedef CXCursorVisitor = ffi.Int32 Function( + CXCursor, + CXCursor, + ffi.Pointer, +); + +typedef CXFieldVisitor = ffi.Int32 Function( + CXCursor, + ffi.Pointer, +); + +/// Uniquely identifies a CXFile, that refers to the same underlying file, across an indexing session. +class CXFileUniqueID extends ffi.Struct { + @ffi.Uint64() + int _data_item_0; + @ffi.Uint64() + int _data_item_1; + @ffi.Uint64() + int _data_item_2; + + /// helper for array, supports `[]` operator + _ArrayHelper_CXFileUniqueID_data get data => + _ArrayHelper_CXFileUniqueID_data(this, 3); +} + +/// Helper for array data in struct CXFileUniqueID +class _ArrayHelper_CXFileUniqueID_data { + final CXFileUniqueID _struct; + final int length; + _ArrayHelper_CXFileUniqueID_data(this._struct, this.length); + void operator []=(int index, int value) { + switch (index) { + case 0: + _struct._data_item_0 = value; + break; + case 1: + _struct._data_item_1 = value; + break; + case 2: + _struct._data_item_2 = value; + break; + default: + throw RangeError('Index $index must be in the range [0..2].'); + } + } + + int operator [](int index) { + switch (index) { + case 0: + return _struct._data_item_0; + case 1: + return _struct._data_item_1; + case 2: + return _struct._data_item_2; + default: + throw RangeError('Index $index must be in the range [0..2].'); + } + } + + @override + String toString() { + if (length == 0) return '[]'; + final sb = StringBuffer('['); + sb.write(this[0]); + for (var i = 1; i < length; i++) { + sb.write(','); + sb.write(this[i]); + } + sb.write(']'); + return sb.toString(); + } +} + +class CXGlobalOptFlags { + static const int CXGlobalOpt_None = 0; + static const int CXGlobalOpt_ThreadBackgroundPriorityForIndexing = 1; + static const int CXGlobalOpt_ThreadBackgroundPriorityForEditing = 2; + static const int CXGlobalOpt_ThreadBackgroundPriorityForAll = 3; +} + +class CXIdxAttrInfo extends ffi.Struct {} + +class CXIdxBaseClassInfo extends ffi.Struct {} + +class CXIdxCXXClassDeclInfo extends ffi.Struct { + ffi.Pointer declInfo; + + ffi.Pointer> bases; + + @ffi.Uint32() + int numBases; +} + +class CXIdxContainerInfo extends ffi.Struct {} + +class CXIdxDeclInfo extends ffi.Struct {} + +class CXIdxEntityInfo extends ffi.Struct {} + +/// Data for IndexerCallbacks#indexEntityReference. +class CXIdxEntityRefInfo extends ffi.Struct {} + +class CXIdxIBOutletCollectionAttrInfo extends ffi.Struct {} + +/// Data for IndexerCallbacks#importedASTFile. +class CXIdxImportedASTFileInfo extends ffi.Struct {} + +/// Data for ppIncludedFile callback. +class CXIdxIncludedFileInfo extends ffi.Struct {} + +/// Source location passed to index callbacks. +class CXIdxLoc extends ffi.Struct { + ffi.Pointer _ptr_data_item_0; + ffi.Pointer _ptr_data_item_1; + ffi.Pointer _ptr_data_item_2; + + /// helper for array, supports `[]` operator + _ArrayHelper_CXIdxLoc_ptr_data get ptr_data => + _ArrayHelper_CXIdxLoc_ptr_data(this, 3); + @ffi.Uint32() + int int_data; +} + +/// Helper for array ptr_data in struct CXIdxLoc +class _ArrayHelper_CXIdxLoc_ptr_data { + final CXIdxLoc _struct; + final int length; + _ArrayHelper_CXIdxLoc_ptr_data(this._struct, this.length); + void operator []=(int index, ffi.Pointer value) { + switch (index) { + case 0: + _struct._ptr_data_item_0 = value; + break; + case 1: + _struct._ptr_data_item_1 = value; + break; + case 2: + _struct._ptr_data_item_2 = value; + break; + default: + throw RangeError('Index $index must be in the range [0..2].'); + } + } + + ffi.Pointer operator [](int index) { + switch (index) { + case 0: + return _struct._ptr_data_item_0; + case 1: + return _struct._ptr_data_item_1; + case 2: + return _struct._ptr_data_item_2; + default: + throw RangeError('Index $index must be in the range [0..2].'); + } + } + + @override + String toString() { + if (length == 0) return '[]'; + final sb = StringBuffer('['); + sb.write(this[0]); + for (var i = 1; i < length; i++) { + sb.write(','); + sb.write(this[i]); + } + sb.write(']'); + return sb.toString(); + } +} + +class CXIdxObjCCategoryDeclInfo extends ffi.Struct {} + +class CXIdxObjCContainerDeclInfo extends ffi.Struct { + ffi.Pointer declInfo; + + @ffi.Int32() + int kind; +} + +class CXIdxObjCInterfaceDeclInfo extends ffi.Struct { + ffi.Pointer containerInfo; + + ffi.Pointer superInfo; + + ffi.Pointer protocols; +} + +class CXIdxObjCPropertyDeclInfo extends ffi.Struct { + ffi.Pointer declInfo; + + ffi.Pointer getter; + + ffi.Pointer setter; +} + +class CXIdxObjCProtocolRefInfo extends ffi.Struct {} + +class CXIdxObjCProtocolRefListInfo extends ffi.Struct { + ffi.Pointer> protocols; + + @ffi.Uint32() + int numProtocols; +} + +typedef CXInclusionVisitor = ffi.Void Function( + ffi.Pointer, + ffi.Pointer, + ffi.Uint32, + ffi.Pointer, +); + +/// Describes the availability of a given entity on a particular platform, e.g., a particular class might only be available on Mac OS 10.7 or newer. +class CXPlatformAvailability extends ffi.Struct {} + +/// Identifies a specific source location within a translation unit. +class CXSourceLocation extends ffi.Struct { + ffi.Pointer _ptr_data_item_0; + ffi.Pointer _ptr_data_item_1; + ffi.Pointer _ptr_data_item_2; + + /// helper for array, supports `[]` operator + _ArrayHelper_CXSourceLocation_ptr_data get ptr_data => + _ArrayHelper_CXSourceLocation_ptr_data(this, 3); + @ffi.Uint32() + int int_data; +} + +/// Helper for array ptr_data in struct CXSourceLocation +class _ArrayHelper_CXSourceLocation_ptr_data { + final CXSourceLocation _struct; + final int length; + _ArrayHelper_CXSourceLocation_ptr_data(this._struct, this.length); + void operator []=(int index, ffi.Pointer value) { + switch (index) { + case 0: + _struct._ptr_data_item_0 = value; + break; + case 1: + _struct._ptr_data_item_1 = value; + break; + case 2: + _struct._ptr_data_item_2 = value; + break; + default: + throw RangeError('Index $index must be in the range [0..2].'); + } + } + + ffi.Pointer operator [](int index) { + switch (index) { + case 0: + return _struct._ptr_data_item_0; + case 1: + return _struct._ptr_data_item_1; + case 2: + return _struct._ptr_data_item_2; + default: + throw RangeError('Index $index must be in the range [0..2].'); + } + } + + @override + String toString() { + if (length == 0) return '[]'; + final sb = StringBuffer('['); + sb.write(this[0]); + for (var i = 1; i < length; i++) { + sb.write(','); + sb.write(this[i]); + } + sb.write(']'); + return sb.toString(); + } +} + +/// Identifies a half-open character range in the source code. +class CXSourceRange extends ffi.Struct { + ffi.Pointer _ptr_data_item_0; + ffi.Pointer _ptr_data_item_1; + ffi.Pointer _ptr_data_item_2; + + /// helper for array, supports `[]` operator + _ArrayHelper_CXSourceRange_ptr_data get ptr_data => + _ArrayHelper_CXSourceRange_ptr_data(this, 3); + @ffi.Uint32() + int begin_int_data; + + @ffi.Uint32() + int end_int_data; +} + +/// Helper for array ptr_data in struct CXSourceRange +class _ArrayHelper_CXSourceRange_ptr_data { + final CXSourceRange _struct; + final int length; + _ArrayHelper_CXSourceRange_ptr_data(this._struct, this.length); + void operator []=(int index, ffi.Pointer value) { + switch (index) { + case 0: + _struct._ptr_data_item_0 = value; + break; + case 1: + _struct._ptr_data_item_1 = value; + break; + case 2: + _struct._ptr_data_item_2 = value; + break; + default: + throw RangeError('Index $index must be in the range [0..2].'); + } + } + + ffi.Pointer operator [](int index) { + switch (index) { + case 0: + return _struct._ptr_data_item_0; + case 1: + return _struct._ptr_data_item_1; + case 2: + return _struct._ptr_data_item_2; + default: + throw RangeError('Index $index must be in the range [0..2].'); + } + } + + @override + String toString() { + if (length == 0) return '[]'; + final sb = StringBuffer('['); + sb.write(this[0]); + for (var i = 1; i < length; i++) { + sb.write(','); + sb.write(this[i]); + } + sb.write(']'); + return sb.toString(); + } +} + +/// Identifies an array of ranges. +class CXSourceRangeList extends ffi.Struct { + @ffi.Uint32() + int count; + + ffi.Pointer ranges; +} + +/// A character string. +class CXString extends ffi.Struct { + ffi.Pointer data; + + @ffi.Uint32() + int private_flags; +} + +class CXStringSet extends ffi.Struct { + ffi.Pointer Strings; + + @ffi.Uint32() + int Count; +} + +/// The memory usage of a CXTranslationUnit, broken into categories. +class CXTUResourceUsage extends ffi.Struct { + ffi.Pointer data; + + @ffi.Uint32() + int numEntries; + + ffi.Pointer entries; +} + +class CXTUResourceUsageEntry extends ffi.Struct { + @ffi.Int32() + int kind; + + @ffi.Uint64() + int amount; +} + +class CXTargetInfoImpl extends ffi.Struct {} + +/// Describes a single preprocessing token. +class CXToken extends ffi.Struct { + @ffi.Uint32() + int _int_data_item_0; + @ffi.Uint32() + int _int_data_item_1; + @ffi.Uint32() + int _int_data_item_2; + + /// helper for array, supports `[]` operator + _ArrayHelper_CXToken_int_data get int_data => + _ArrayHelper_CXToken_int_data(this, 3); + ffi.Pointer ptr_data; +} + +/// Helper for array int_data in struct CXToken +class _ArrayHelper_CXToken_int_data { + final CXToken _struct; + final int length; + _ArrayHelper_CXToken_int_data(this._struct, this.length); + void operator []=(int index, int value) { + switch (index) { + case 0: + _struct._int_data_item_0 = value; + break; + case 1: + _struct._int_data_item_1 = value; + break; + case 2: + _struct._int_data_item_2 = value; + break; + default: + throw RangeError('Index $index must be in the range [0..2].'); + } + } + + int operator [](int index) { + switch (index) { + case 0: + return _struct._int_data_item_0; + case 1: + return _struct._int_data_item_1; + case 2: + return _struct._int_data_item_2; + default: + throw RangeError('Index $index must be in the range [0..2].'); + } + } + + @override + String toString() { + if (length == 0) return '[]'; + final sb = StringBuffer('['); + sb.write(this[0]); + for (var i = 1; i < length; i++) { + sb.write(','); + sb.write(this[i]); + } + sb.write(']'); + return sb.toString(); + } +} + +class CXTranslationUnitImpl extends ffi.Struct {} + +/// The type of an element in the abstract syntax tree. +class CXType extends ffi.Struct { + @ffi.Int32() + int kind; + + ffi.Pointer _data_item_0; + ffi.Pointer _data_item_1; + ffi.Pointer _data_item_2; + + /// helper for array, supports `[]` operator + _ArrayHelper_CXType_data get data => _ArrayHelper_CXType_data(this, 3); +} + +/// Helper for array data in struct CXType +class _ArrayHelper_CXType_data { + final CXType _struct; + final int length; + _ArrayHelper_CXType_data(this._struct, this.length); + void operator []=(int index, ffi.Pointer value) { + switch (index) { + case 0: + _struct._data_item_0 = value; + break; + case 1: + _struct._data_item_1 = value; + break; + case 2: + _struct._data_item_2 = value; + break; + default: + throw RangeError('Index $index must be in the range [0..2].'); + } + } + + ffi.Pointer operator [](int index) { + switch (index) { + case 0: + return _struct._data_item_0; + case 1: + return _struct._data_item_1; + case 2: + return _struct._data_item_2; + default: + throw RangeError('Index $index must be in the range [0..2].'); + } + } + + @override + String toString() { + if (length == 0) return '[]'; + final sb = StringBuffer('['); + sb.write(this[0]); + for (var i = 1; i < length; i++) { + sb.write(','); + sb.write(this[i]); + } + sb.write(']'); + return sb.toString(); + } +} + +/// Describes the kind of type +class CXTypeKind { + static const int CXType_Invalid = 0; + static const int CXType_Unexposed = 1; + static const int CXType_Void = 2; + static const int CXType_Bool = 3; + static const int CXType_Char_U = 4; + static const int CXType_UChar = 5; + static const int CXType_Char16 = 6; + static const int CXType_Char32 = 7; + static const int CXType_UShort = 8; + static const int CXType_UInt = 9; + static const int CXType_ULong = 10; + static const int CXType_ULongLong = 11; + static const int CXType_UInt128 = 12; + static const int CXType_Char_S = 13; + static const int CXType_SChar = 14; + static const int CXType_WChar = 15; + static const int CXType_Short = 16; + static const int CXType_Int = 17; + static const int CXType_Long = 18; + static const int CXType_LongLong = 19; + static const int CXType_Int128 = 20; + static const int CXType_Float = 21; + static const int CXType_Double = 22; + static const int CXType_LongDouble = 23; + static const int CXType_NullPtr = 24; + static const int CXType_Overload = 25; + static const int CXType_Dependent = 26; + static const int CXType_ObjCId = 27; + static const int CXType_ObjCClass = 28; + static const int CXType_ObjCSel = 29; + static const int CXType_Float128 = 30; + static const int CXType_Half = 31; + static const int CXType_Float16 = 32; + static const int CXType_ShortAccum = 33; + static const int CXType_Accum = 34; + static const int CXType_LongAccum = 35; + static const int CXType_UShortAccum = 36; + static const int CXType_UAccum = 37; + static const int CXType_ULongAccum = 38; + static const int CXType_FirstBuiltin = 2; + static const int CXType_LastBuiltin = 38; + static const int CXType_Complex = 100; + static const int CXType_Pointer = 101; + static const int CXType_BlockPointer = 102; + static const int CXType_LValueReference = 103; + static const int CXType_RValueReference = 104; + static const int CXType_Record = 105; + static const int CXType_Enum = 106; + static const int CXType_Typedef = 107; + static const int CXType_ObjCInterface = 108; + static const int CXType_ObjCObjectPointer = 109; + static const int CXType_FunctionNoProto = 110; + static const int CXType_FunctionProto = 111; + static const int CXType_ConstantArray = 112; + static const int CXType_Vector = 113; + static const int CXType_IncompleteArray = 114; + static const int CXType_VariableArray = 115; + static const int CXType_DependentSizedArray = 116; + static const int CXType_MemberPointer = 117; + static const int CXType_Auto = 118; + static const int CXType_Elaborated = 119; + static const int CXType_Pipe = 120; + static const int CXType_OCLImage1dRO = 121; + static const int CXType_OCLImage1dArrayRO = 122; + static const int CXType_OCLImage1dBufferRO = 123; + static const int CXType_OCLImage2dRO = 124; + static const int CXType_OCLImage2dArrayRO = 125; + static const int CXType_OCLImage2dDepthRO = 126; + static const int CXType_OCLImage2dArrayDepthRO = 127; + static const int CXType_OCLImage2dMSAARO = 128; + static const int CXType_OCLImage2dArrayMSAARO = 129; + static const int CXType_OCLImage2dMSAADepthRO = 130; + static const int CXType_OCLImage2dArrayMSAADepthRO = 131; + static const int CXType_OCLImage3dRO = 132; + static const int CXType_OCLImage1dWO = 133; + static const int CXType_OCLImage1dArrayWO = 134; + static const int CXType_OCLImage1dBufferWO = 135; + static const int CXType_OCLImage2dWO = 136; + static const int CXType_OCLImage2dArrayWO = 137; + static const int CXType_OCLImage2dDepthWO = 138; + static const int CXType_OCLImage2dArrayDepthWO = 139; + static const int CXType_OCLImage2dMSAAWO = 140; + static const int CXType_OCLImage2dArrayMSAAWO = 141; + static const int CXType_OCLImage2dMSAADepthWO = 142; + static const int CXType_OCLImage2dArrayMSAADepthWO = 143; + static const int CXType_OCLImage3dWO = 144; + static const int CXType_OCLImage1dRW = 145; + static const int CXType_OCLImage1dArrayRW = 146; + static const int CXType_OCLImage1dBufferRW = 147; + static const int CXType_OCLImage2dRW = 148; + static const int CXType_OCLImage2dArrayRW = 149; + static const int CXType_OCLImage2dDepthRW = 150; + static const int CXType_OCLImage2dArrayDepthRW = 151; + static const int CXType_OCLImage2dMSAARW = 152; + static const int CXType_OCLImage2dArrayMSAARW = 153; + static const int CXType_OCLImage2dMSAADepthRW = 154; + static const int CXType_OCLImage2dArrayMSAADepthRW = 155; + static const int CXType_OCLImage3dRW = 156; + static const int CXType_OCLSampler = 157; + static const int CXType_OCLEvent = 158; + static const int CXType_OCLQueue = 159; + static const int CXType_OCLReserveID = 160; + static const int CXType_ObjCObject = 161; + static const int CXType_ObjCTypeParam = 162; + static const int CXType_Attributed = 163; + static const int CXType_OCLIntelSubgroupAVCMcePayload = 164; + static const int CXType_OCLIntelSubgroupAVCImePayload = 165; + static const int CXType_OCLIntelSubgroupAVCRefPayload = 166; + static const int CXType_OCLIntelSubgroupAVCSicPayload = 167; + static const int CXType_OCLIntelSubgroupAVCMceResult = 168; + static const int CXType_OCLIntelSubgroupAVCImeResult = 169; + static const int CXType_OCLIntelSubgroupAVCRefResult = 170; + static const int CXType_OCLIntelSubgroupAVCSicResult = 171; + static const int CXType_OCLIntelSubgroupAVCImeResultSingleRefStreamout = 172; + static const int CXType_OCLIntelSubgroupAVCImeResultDualRefStreamout = 173; + static const int CXType_OCLIntelSubgroupAVCImeSingleRefStreamin = 174; + static const int CXType_OCLIntelSubgroupAVCImeDualRefStreamin = 175; + static const int CXType_ExtVector = 176; +} + +/// Provides the contents of a file that has not yet been saved to disk. +class CXUnsavedFile extends ffi.Struct { + ffi.Pointer Filename; + + ffi.Pointer Contents; + + @ffi.Uint64() + int Length; +} + +/// Describes a version number of the form major.minor.subminor. +class CXVersion extends ffi.Struct { + @ffi.Int32() + int Major; + + @ffi.Int32() + int Minor; + + @ffi.Int32() + int Subminor; +} + +/// A group of callbacks used by #clang_indexSourceFile and #clang_indexTranslationUnit. +class IndexerCallbacks extends ffi.Struct { + ffi.Pointer> abortQuery; + + ffi.Pointer> diagnostic; + + ffi.Pointer> enteredMainFile; + + ffi.Pointer> ppIncludedFile; + + ffi.Pointer> importedASTFile; + + ffi.Pointer> startedTranslationUnit; + + ffi.Pointer> indexDeclaration; + + ffi.Pointer> indexEntityReference; +} + +typedef ModifiedCXCursorVisitor = ffi.Int32 Function( + ffi.Pointer, + ffi.Pointer, + ffi.Pointer, +); + +typedef _typedefC_noname_1 = ffi.Void Function( + ffi.Pointer, +); + +typedef _typedefC_noname_10 = ffi.Void Function( + ffi.Pointer, + ffi.Pointer, +); + +typedef _typedefC_noname_2 = ffi.Int32 Function( + ffi.Pointer, + CXCursor, + CXSourceRange, +); + +typedef _typedefC_noname_3 = ffi.Int32 Function( + ffi.Pointer, + ffi.Pointer, +); + +typedef _typedefC_noname_4 = ffi.Void Function( + ffi.Pointer, + ffi.Pointer, + ffi.Pointer, +); + +typedef _typedefC_noname_5 = ffi.Pointer Function( + ffi.Pointer, + ffi.Pointer, + ffi.Pointer, +); + +typedef _typedefC_noname_6 = ffi.Pointer Function( + ffi.Pointer, + ffi.Pointer, +); + +typedef _typedefC_noname_7 = ffi.Pointer Function( + ffi.Pointer, + ffi.Pointer, +); + +typedef _typedefC_noname_8 = ffi.Pointer Function( + ffi.Pointer, + ffi.Pointer, +); + +typedef _typedefC_noname_9 = ffi.Void Function( + ffi.Pointer, + ffi.Pointer, +); + +/// Gets the general options associated with a CXIndex. +int clang_CXIndex_getGlobalOptions( + ffi.Pointer arg0, +) { + return _clang_CXIndex_getGlobalOptions( + arg0, + ); +} + +final _dart_clang_CXIndex_getGlobalOptions _clang_CXIndex_getGlobalOptions = + _dylib.lookupFunction<_c_clang_CXIndex_getGlobalOptions, + _dart_clang_CXIndex_getGlobalOptions>('clang_CXIndex_getGlobalOptions'); + +typedef _c_clang_CXIndex_getGlobalOptions = ffi.Uint32 Function( + ffi.Pointer arg0, +); + +typedef _dart_clang_CXIndex_getGlobalOptions = int Function( + ffi.Pointer arg0, +); + +/// Sets general options associated with a CXIndex. +void clang_CXIndex_setGlobalOptions( + ffi.Pointer arg0, + int options, +) { + return _clang_CXIndex_setGlobalOptions( + arg0, + options, + ); +} + +final _dart_clang_CXIndex_setGlobalOptions _clang_CXIndex_setGlobalOptions = + _dylib.lookupFunction<_c_clang_CXIndex_setGlobalOptions, + _dart_clang_CXIndex_setGlobalOptions>('clang_CXIndex_setGlobalOptions'); + +typedef _c_clang_CXIndex_setGlobalOptions = ffi.Void Function( + ffi.Pointer arg0, + ffi.Uint32 options, +); + +typedef _dart_clang_CXIndex_setGlobalOptions = void Function( + ffi.Pointer arg0, + int options, +); + +/// Sets the invocation emission path option in a CXIndex. +void clang_CXIndex_setInvocationEmissionPathOption( + ffi.Pointer arg0, + ffi.Pointer Path, +) { + return _clang_CXIndex_setInvocationEmissionPathOption( + arg0, + Path, + ); +} + +final _dart_clang_CXIndex_setInvocationEmissionPathOption + _clang_CXIndex_setInvocationEmissionPathOption = _dylib.lookupFunction< + _c_clang_CXIndex_setInvocationEmissionPathOption, + _dart_clang_CXIndex_setInvocationEmissionPathOption>( + 'clang_CXIndex_setInvocationEmissionPathOption'); + +typedef _c_clang_CXIndex_setInvocationEmissionPathOption = ffi.Void Function( + ffi.Pointer arg0, + ffi.Pointer Path, +); + +typedef _dart_clang_CXIndex_setInvocationEmissionPathOption = void Function( + ffi.Pointer arg0, + ffi.Pointer Path, +); + +ffi.Pointer clang_Cursor_getArgument_wrap( + ffi.Pointer cursor, + int i, +) { + return _clang_Cursor_getArgument_wrap( + cursor, + i, + ); +} + +final _dart_clang_Cursor_getArgument_wrap _clang_Cursor_getArgument_wrap = + _dylib.lookupFunction<_c_clang_Cursor_getArgument_wrap, + _dart_clang_Cursor_getArgument_wrap>('clang_Cursor_getArgument_wrap'); + +typedef _c_clang_Cursor_getArgument_wrap = ffi.Pointer Function( + ffi.Pointer cursor, + ffi.Uint32 i, +); + +typedef _dart_clang_Cursor_getArgument_wrap = ffi.Pointer Function( + ffi.Pointer cursor, + int i, +); + +/// Returns the first paragraph of doxygen doc comment. +ffi.Pointer clang_Cursor_getBriefCommentText_wrap( + ffi.Pointer cursor, +) { + return _clang_Cursor_getBriefCommentText_wrap( + cursor, + ); +} + +final _dart_clang_Cursor_getBriefCommentText_wrap + _clang_Cursor_getBriefCommentText_wrap = _dylib.lookupFunction< + _c_clang_Cursor_getBriefCommentText_wrap, + _dart_clang_Cursor_getBriefCommentText_wrap>( + 'clang_Cursor_getBriefCommentText_wrap'); + +typedef _c_clang_Cursor_getBriefCommentText_wrap = ffi.Pointer + Function( + ffi.Pointer cursor, +); + +typedef _dart_clang_Cursor_getBriefCommentText_wrap = ffi.Pointer + Function( + ffi.Pointer cursor, +); + +int clang_Cursor_getNumArguments_wrap( + ffi.Pointer cursor, +) { + return _clang_Cursor_getNumArguments_wrap( + cursor, + ); +} + +final _dart_clang_Cursor_getNumArguments_wrap + _clang_Cursor_getNumArguments_wrap = _dylib.lookupFunction< + _c_clang_Cursor_getNumArguments_wrap, + _dart_clang_Cursor_getNumArguments_wrap>( + 'clang_Cursor_getNumArguments_wrap'); + +typedef _c_clang_Cursor_getNumArguments_wrap = ffi.Int32 Function( + ffi.Pointer cursor, +); + +typedef _dart_clang_Cursor_getNumArguments_wrap = int Function( + ffi.Pointer cursor, +); + +/// Disposes the created Eval memory. +void clang_EvalResult_dispose( + ffi.Pointer E, +) { + return _clang_EvalResult_dispose( + E, + ); +} + +final _dart_clang_EvalResult_dispose _clang_EvalResult_dispose = + _dylib.lookupFunction<_c_clang_EvalResult_dispose, + _dart_clang_EvalResult_dispose>('clang_EvalResult_dispose'); + +typedef _c_clang_EvalResult_dispose = ffi.Void Function( + ffi.Pointer E, +); + +typedef _dart_clang_EvalResult_dispose = void Function( + ffi.Pointer E, +); + +/// Returns the evaluation result as double if the kind is double. +double clang_EvalResult_getAsDouble( + ffi.Pointer E, +) { + return _clang_EvalResult_getAsDouble( + E, + ); +} + +final _dart_clang_EvalResult_getAsDouble _clang_EvalResult_getAsDouble = + _dylib.lookupFunction<_c_clang_EvalResult_getAsDouble, + _dart_clang_EvalResult_getAsDouble>('clang_EvalResult_getAsDouble'); + +typedef _c_clang_EvalResult_getAsDouble = ffi.Double Function( + ffi.Pointer E, +); + +typedef _dart_clang_EvalResult_getAsDouble = double Function( + ffi.Pointer E, +); + +/// Returns the evaluation result as integer if the kind is Int. +int clang_EvalResult_getAsInt( + ffi.Pointer E, +) { + return _clang_EvalResult_getAsInt( + E, + ); +} + +final _dart_clang_EvalResult_getAsInt _clang_EvalResult_getAsInt = + _dylib.lookupFunction<_c_clang_EvalResult_getAsInt, + _dart_clang_EvalResult_getAsInt>('clang_EvalResult_getAsInt'); + +typedef _c_clang_EvalResult_getAsInt = ffi.Int32 Function( + ffi.Pointer E, +); + +typedef _dart_clang_EvalResult_getAsInt = int Function( + ffi.Pointer E, +); + +/// Returns the evaluation result as a long long integer if the kind is Int. This prevents overflows that may happen if the result is returned with clang_EvalResult_getAsInt. +int clang_EvalResult_getAsLongLong( + ffi.Pointer E, +) { + return _clang_EvalResult_getAsLongLong( + E, + ); +} + +final _dart_clang_EvalResult_getAsLongLong _clang_EvalResult_getAsLongLong = + _dylib.lookupFunction<_c_clang_EvalResult_getAsLongLong, + _dart_clang_EvalResult_getAsLongLong>('clang_EvalResult_getAsLongLong'); + +typedef _c_clang_EvalResult_getAsLongLong = ffi.Int64 Function( + ffi.Pointer E, +); + +typedef _dart_clang_EvalResult_getAsLongLong = int Function( + ffi.Pointer E, +); + +/// Returns the evaluation result as a constant string if the kind is other than Int or float. User must not free this pointer, instead call clang_EvalResult_dispose on the CXEvalResult returned by clang_Cursor_Evaluate. +ffi.Pointer clang_EvalResult_getAsStr( + ffi.Pointer E, +) { + return _clang_EvalResult_getAsStr( + E, + ); +} + +final _dart_clang_EvalResult_getAsStr _clang_EvalResult_getAsStr = + _dylib.lookupFunction<_c_clang_EvalResult_getAsStr, + _dart_clang_EvalResult_getAsStr>('clang_EvalResult_getAsStr'); + +typedef _c_clang_EvalResult_getAsStr = ffi.Pointer Function( + ffi.Pointer E, +); + +typedef _dart_clang_EvalResult_getAsStr = ffi.Pointer Function( + ffi.Pointer E, +); + +/// Returns the evaluation result as an unsigned integer if the kind is Int and clang_EvalResult_isUnsignedInt is non-zero. +int clang_EvalResult_getAsUnsigned( + ffi.Pointer E, +) { + return _clang_EvalResult_getAsUnsigned( + E, + ); +} + +final _dart_clang_EvalResult_getAsUnsigned _clang_EvalResult_getAsUnsigned = + _dylib.lookupFunction<_c_clang_EvalResult_getAsUnsigned, + _dart_clang_EvalResult_getAsUnsigned>('clang_EvalResult_getAsUnsigned'); + +typedef _c_clang_EvalResult_getAsUnsigned = ffi.Uint64 Function( + ffi.Pointer E, +); + +typedef _dart_clang_EvalResult_getAsUnsigned = int Function( + ffi.Pointer E, +); + +/// Returns the kind of the evaluated result. +int clang_EvalResult_getKind( + ffi.Pointer E, +) { + return _clang_EvalResult_getKind( + E, + ); +} + +final _dart_clang_EvalResult_getKind _clang_EvalResult_getKind = + _dylib.lookupFunction<_c_clang_EvalResult_getKind, + _dart_clang_EvalResult_getKind>('clang_EvalResult_getKind'); + +typedef _c_clang_EvalResult_getKind = ffi.Int32 Function( + ffi.Pointer E, +); + +typedef _dart_clang_EvalResult_getKind = int Function( + ffi.Pointer E, +); + +/// Returns a non-zero value if the kind is Int and the evaluation result resulted in an unsigned integer. +int clang_EvalResult_isUnsignedInt( + ffi.Pointer E, +) { + return _clang_EvalResult_isUnsignedInt( + E, + ); +} + +final _dart_clang_EvalResult_isUnsignedInt _clang_EvalResult_isUnsignedInt = + _dylib.lookupFunction<_c_clang_EvalResult_isUnsignedInt, + _dart_clang_EvalResult_isUnsignedInt>('clang_EvalResult_isUnsignedInt'); + +typedef _c_clang_EvalResult_isUnsignedInt = ffi.Uint32 Function( + ffi.Pointer E, +); + +typedef _dart_clang_EvalResult_isUnsignedInt = int Function( + ffi.Pointer E, +); + +/// Returns non-zero if the file1 and file2 point to the same file, or they are both NULL. +int clang_File_isEqual( + ffi.Pointer file1, + ffi.Pointer file2, +) { + return _clang_File_isEqual( + file1, + file2, + ); +} + +final _dart_clang_File_isEqual _clang_File_isEqual = + _dylib.lookupFunction<_c_clang_File_isEqual, _dart_clang_File_isEqual>( + 'clang_File_isEqual'); + +typedef _c_clang_File_isEqual = ffi.Int32 Function( + ffi.Pointer file1, + ffi.Pointer file2, +); + +typedef _dart_clang_File_isEqual = int Function( + ffi.Pointer file1, + ffi.Pointer file2, +); + +/// An indexing action/session, to be applied to one or multiple translation units. +ffi.Pointer clang_IndexAction_create( + ffi.Pointer CIdx, +) { + return _clang_IndexAction_create( + CIdx, + ); +} + +final _dart_clang_IndexAction_create _clang_IndexAction_create = + _dylib.lookupFunction<_c_clang_IndexAction_create, + _dart_clang_IndexAction_create>('clang_IndexAction_create'); + +typedef _c_clang_IndexAction_create = ffi.Pointer Function( + ffi.Pointer CIdx, +); + +typedef _dart_clang_IndexAction_create = ffi.Pointer Function( + ffi.Pointer CIdx, +); + +/// Destroy the given index action. +void clang_IndexAction_dispose( + ffi.Pointer arg0, +) { + return _clang_IndexAction_dispose( + arg0, + ); +} + +final _dart_clang_IndexAction_dispose _clang_IndexAction_dispose = + _dylib.lookupFunction<_c_clang_IndexAction_dispose, + _dart_clang_IndexAction_dispose>('clang_IndexAction_dispose'); + +typedef _c_clang_IndexAction_dispose = ffi.Void Function( + ffi.Pointer arg0, +); + +typedef _dart_clang_IndexAction_dispose = void Function( + ffi.Pointer arg0, +); + +/// Returns the module file where the provided module object came from. +ffi.Pointer clang_Module_getASTFile( + ffi.Pointer Module, +) { + return _clang_Module_getASTFile( + Module, + ); +} + +final _dart_clang_Module_getASTFile _clang_Module_getASTFile = _dylib + .lookupFunction<_c_clang_Module_getASTFile, _dart_clang_Module_getASTFile>( + 'clang_Module_getASTFile'); + +typedef _c_clang_Module_getASTFile = ffi.Pointer Function( + ffi.Pointer Module, +); + +typedef _dart_clang_Module_getASTFile = ffi.Pointer Function( + ffi.Pointer Module, +); + +/// Returns the number of top level headers associated with this module. +int clang_Module_getNumTopLevelHeaders( + ffi.Pointer arg0, + ffi.Pointer Module, +) { + return _clang_Module_getNumTopLevelHeaders( + arg0, + Module, + ); +} + +final _dart_clang_Module_getNumTopLevelHeaders + _clang_Module_getNumTopLevelHeaders = _dylib.lookupFunction< + _c_clang_Module_getNumTopLevelHeaders, + _dart_clang_Module_getNumTopLevelHeaders>( + 'clang_Module_getNumTopLevelHeaders'); + +typedef _c_clang_Module_getNumTopLevelHeaders = ffi.Uint32 Function( + ffi.Pointer arg0, + ffi.Pointer Module, +); + +typedef _dart_clang_Module_getNumTopLevelHeaders = int Function( + ffi.Pointer arg0, + ffi.Pointer Module, +); + +/// Returns the parent of a sub-module or NULL if the given module is top-level, e.g. for 'std.vector' it will return the 'std' module. +ffi.Pointer clang_Module_getParent( + ffi.Pointer Module, +) { + return _clang_Module_getParent( + Module, + ); +} + +final _dart_clang_Module_getParent _clang_Module_getParent = _dylib + .lookupFunction<_c_clang_Module_getParent, _dart_clang_Module_getParent>( + 'clang_Module_getParent'); + +typedef _c_clang_Module_getParent = ffi.Pointer Function( + ffi.Pointer Module, +); + +typedef _dart_clang_Module_getParent = ffi.Pointer Function( + ffi.Pointer Module, +); + +/// Returns the specified top level header associated with the module. +ffi.Pointer clang_Module_getTopLevelHeader( + ffi.Pointer arg0, + ffi.Pointer Module, + int Index, +) { + return _clang_Module_getTopLevelHeader( + arg0, + Module, + Index, + ); +} + +final _dart_clang_Module_getTopLevelHeader _clang_Module_getTopLevelHeader = + _dylib.lookupFunction<_c_clang_Module_getTopLevelHeader, + _dart_clang_Module_getTopLevelHeader>('clang_Module_getTopLevelHeader'); + +typedef _c_clang_Module_getTopLevelHeader = ffi.Pointer Function( + ffi.Pointer arg0, + ffi.Pointer Module, + ffi.Uint32 Index, +); + +typedef _dart_clang_Module_getTopLevelHeader = ffi.Pointer Function( + ffi.Pointer arg0, + ffi.Pointer Module, + int Index, +); + +/// Returns non-zero if the module is a system one. +int clang_Module_isSystem( + ffi.Pointer Module, +) { + return _clang_Module_isSystem( + Module, + ); +} + +final _dart_clang_Module_isSystem _clang_Module_isSystem = _dylib + .lookupFunction<_c_clang_Module_isSystem, _dart_clang_Module_isSystem>( + 'clang_Module_isSystem'); + +typedef _c_clang_Module_isSystem = ffi.Int32 Function( + ffi.Pointer Module, +); + +typedef _dart_clang_Module_isSystem = int Function( + ffi.Pointer Module, +); + +/// Release a printing policy. +void clang_PrintingPolicy_dispose( + ffi.Pointer Policy, +) { + return _clang_PrintingPolicy_dispose( + Policy, + ); +} + +final _dart_clang_PrintingPolicy_dispose _clang_PrintingPolicy_dispose = + _dylib.lookupFunction<_c_clang_PrintingPolicy_dispose, + _dart_clang_PrintingPolicy_dispose>('clang_PrintingPolicy_dispose'); + +typedef _c_clang_PrintingPolicy_dispose = ffi.Void Function( + ffi.Pointer Policy, +); + +typedef _dart_clang_PrintingPolicy_dispose = void Function( + ffi.Pointer Policy, +); + +/// Get a property value for the given printing policy. +int clang_PrintingPolicy_getProperty( + ffi.Pointer Policy, + int Property, +) { + return _clang_PrintingPolicy_getProperty( + Policy, + Property, + ); +} + +final _dart_clang_PrintingPolicy_getProperty _clang_PrintingPolicy_getProperty = + _dylib.lookupFunction<_c_clang_PrintingPolicy_getProperty, + _dart_clang_PrintingPolicy_getProperty>( + 'clang_PrintingPolicy_getProperty'); + +typedef _c_clang_PrintingPolicy_getProperty = ffi.Uint32 Function( + ffi.Pointer Policy, + ffi.Int32 Property, +); + +typedef _dart_clang_PrintingPolicy_getProperty = int Function( + ffi.Pointer Policy, + int Property, +); + +/// Set a property value for the given printing policy. +void clang_PrintingPolicy_setProperty( + ffi.Pointer Policy, + int Property, + int Value, +) { + return _clang_PrintingPolicy_setProperty( + Policy, + Property, + Value, + ); +} + +final _dart_clang_PrintingPolicy_setProperty _clang_PrintingPolicy_setProperty = + _dylib.lookupFunction<_c_clang_PrintingPolicy_setProperty, + _dart_clang_PrintingPolicy_setProperty>( + 'clang_PrintingPolicy_setProperty'); + +typedef _c_clang_PrintingPolicy_setProperty = ffi.Void Function( + ffi.Pointer Policy, + ffi.Int32 Property, + ffi.Uint32 Value, +); + +typedef _dart_clang_PrintingPolicy_setProperty = void Function( + ffi.Pointer Policy, + int Property, + int Value, +); + +/// Destroy the CXTargetInfo object. +void clang_TargetInfo_dispose( + ffi.Pointer Info, +) { + return _clang_TargetInfo_dispose( + Info, + ); +} + +final _dart_clang_TargetInfo_dispose _clang_TargetInfo_dispose = + _dylib.lookupFunction<_c_clang_TargetInfo_dispose, + _dart_clang_TargetInfo_dispose>('clang_TargetInfo_dispose'); + +typedef _c_clang_TargetInfo_dispose = ffi.Void Function( + ffi.Pointer Info, +); + +typedef _dart_clang_TargetInfo_dispose = void Function( + ffi.Pointer Info, +); + +/// Get the pointer width of the target in bits. +int clang_TargetInfo_getPointerWidth( + ffi.Pointer Info, +) { + return _clang_TargetInfo_getPointerWidth( + Info, + ); +} + +final _dart_clang_TargetInfo_getPointerWidth _clang_TargetInfo_getPointerWidth = + _dylib.lookupFunction<_c_clang_TargetInfo_getPointerWidth, + _dart_clang_TargetInfo_getPointerWidth>( + 'clang_TargetInfo_getPointerWidth'); + +typedef _c_clang_TargetInfo_getPointerWidth = ffi.Int32 Function( + ffi.Pointer Info, +); + +typedef _dart_clang_TargetInfo_getPointerWidth = int Function( + ffi.Pointer Info, +); + +ffi.Pointer clang_Type_getNamedType_wrap( + ffi.Pointer elaboratedType, +) { + return _clang_Type_getNamedType_wrap( + elaboratedType, + ); +} + +final _dart_clang_Type_getNamedType_wrap _clang_Type_getNamedType_wrap = + _dylib.lookupFunction<_c_clang_Type_getNamedType_wrap, + _dart_clang_Type_getNamedType_wrap>('clang_Type_getNamedType_wrap'); + +typedef _c_clang_Type_getNamedType_wrap = ffi.Pointer Function( + ffi.Pointer elaboratedType, +); + +typedef _dart_clang_Type_getNamedType_wrap = ffi.Pointer Function( + ffi.Pointer elaboratedType, +); + +/// Annotate the given set of tokens by providing cursors for each token that can be mapped to a specific entity within the abstract syntax tree. +void clang_annotateTokens( + ffi.Pointer TU, + ffi.Pointer Tokens, + int NumTokens, + ffi.Pointer Cursors, +) { + return _clang_annotateTokens( + TU, + Tokens, + NumTokens, + Cursors, + ); +} + +final _dart_clang_annotateTokens _clang_annotateTokens = + _dylib.lookupFunction<_c_clang_annotateTokens, _dart_clang_annotateTokens>( + 'clang_annotateTokens'); + +typedef _c_clang_annotateTokens = ffi.Void Function( + ffi.Pointer TU, + ffi.Pointer Tokens, + ffi.Uint32 NumTokens, + ffi.Pointer Cursors, +); + +typedef _dart_clang_annotateTokens = void Function( + ffi.Pointer TU, + ffi.Pointer Tokens, + int NumTokens, + ffi.Pointer Cursors, +); + +/// Perform code completion at a given location in a translation unit. +ffi.Pointer clang_codeCompleteAt( + ffi.Pointer TU, + ffi.Pointer complete_filename, + int complete_line, + int complete_column, + ffi.Pointer unsaved_files, + int num_unsaved_files, + int options, +) { + return _clang_codeCompleteAt( + TU, + complete_filename, + complete_line, + complete_column, + unsaved_files, + num_unsaved_files, + options, + ); +} + +final _dart_clang_codeCompleteAt _clang_codeCompleteAt = + _dylib.lookupFunction<_c_clang_codeCompleteAt, _dart_clang_codeCompleteAt>( + 'clang_codeCompleteAt'); + +typedef _c_clang_codeCompleteAt = ffi.Pointer Function( + ffi.Pointer TU, + ffi.Pointer complete_filename, + ffi.Uint32 complete_line, + ffi.Uint32 complete_column, + ffi.Pointer unsaved_files, + ffi.Uint32 num_unsaved_files, + ffi.Uint32 options, +); + +typedef _dart_clang_codeCompleteAt = ffi.Pointer + Function( + ffi.Pointer TU, + ffi.Pointer complete_filename, + int complete_line, + int complete_column, + ffi.Pointer unsaved_files, + int num_unsaved_files, + int options, +); + +/// Returns the cursor kind for the container for the current code completion context. The container is only guaranteed to be set for contexts where a container exists (i.e. member accesses or Objective-C message sends); if there is not a container, this function will return CXCursor_InvalidCode. +int clang_codeCompleteGetContainerKind( + ffi.Pointer Results, + ffi.Pointer IsIncomplete, +) { + return _clang_codeCompleteGetContainerKind( + Results, + IsIncomplete, + ); +} + +final _dart_clang_codeCompleteGetContainerKind + _clang_codeCompleteGetContainerKind = _dylib.lookupFunction< + _c_clang_codeCompleteGetContainerKind, + _dart_clang_codeCompleteGetContainerKind>( + 'clang_codeCompleteGetContainerKind'); + +typedef _c_clang_codeCompleteGetContainerKind = ffi.Int32 Function( + ffi.Pointer Results, + ffi.Pointer IsIncomplete, +); + +typedef _dart_clang_codeCompleteGetContainerKind = int Function( + ffi.Pointer Results, + ffi.Pointer IsIncomplete, +); + +/// Determines what completions are appropriate for the context the given code completion. +int clang_codeCompleteGetContexts( + ffi.Pointer Results, +) { + return _clang_codeCompleteGetContexts( + Results, + ); +} + +final _dart_clang_codeCompleteGetContexts _clang_codeCompleteGetContexts = + _dylib.lookupFunction<_c_clang_codeCompleteGetContexts, + _dart_clang_codeCompleteGetContexts>('clang_codeCompleteGetContexts'); + +typedef _c_clang_codeCompleteGetContexts = ffi.Uint64 Function( + ffi.Pointer Results, +); + +typedef _dart_clang_codeCompleteGetContexts = int Function( + ffi.Pointer Results, +); + +/// Retrieve a diagnostic associated with the given code completion. +ffi.Pointer clang_codeCompleteGetDiagnostic( + ffi.Pointer Results, + int Index, +) { + return _clang_codeCompleteGetDiagnostic( + Results, + Index, + ); +} + +final _dart_clang_codeCompleteGetDiagnostic _clang_codeCompleteGetDiagnostic = + _dylib.lookupFunction<_c_clang_codeCompleteGetDiagnostic, + _dart_clang_codeCompleteGetDiagnostic>( + 'clang_codeCompleteGetDiagnostic'); + +typedef _c_clang_codeCompleteGetDiagnostic = ffi.Pointer Function( + ffi.Pointer Results, + ffi.Uint32 Index, +); + +typedef _dart_clang_codeCompleteGetDiagnostic = ffi.Pointer Function( + ffi.Pointer Results, + int Index, +); + +/// Determine the number of diagnostics produced prior to the location where code completion was performed. +int clang_codeCompleteGetNumDiagnostics( + ffi.Pointer Results, +) { + return _clang_codeCompleteGetNumDiagnostics( + Results, + ); +} + +final _dart_clang_codeCompleteGetNumDiagnostics + _clang_codeCompleteGetNumDiagnostics = _dylib.lookupFunction< + _c_clang_codeCompleteGetNumDiagnostics, + _dart_clang_codeCompleteGetNumDiagnostics>( + 'clang_codeCompleteGetNumDiagnostics'); + +typedef _c_clang_codeCompleteGetNumDiagnostics = ffi.Uint32 Function( + ffi.Pointer Results, +); + +typedef _dart_clang_codeCompleteGetNumDiagnostics = int Function( + ffi.Pointer Results, +); + +/// Creates an empty CXCursorSet. +ffi.Pointer clang_createCXCursorSet() { + return _clang_createCXCursorSet(); +} + +final _dart_clang_createCXCursorSet _clang_createCXCursorSet = _dylib + .lookupFunction<_c_clang_createCXCursorSet, _dart_clang_createCXCursorSet>( + 'clang_createCXCursorSet'); + +typedef _c_clang_createCXCursorSet = ffi.Pointer Function(); + +typedef _dart_clang_createCXCursorSet = ffi.Pointer Function(); + +/// Provides a shared context for creating translation units. +ffi.Pointer clang_createIndex( + int excludeDeclarationsFromPCH, + int displayDiagnostics, +) { + return _clang_createIndex( + excludeDeclarationsFromPCH, + displayDiagnostics, + ); +} + +final _dart_clang_createIndex _clang_createIndex = + _dylib.lookupFunction<_c_clang_createIndex, _dart_clang_createIndex>( + 'clang_createIndex'); + +typedef _c_clang_createIndex = ffi.Pointer Function( + ffi.Int32 excludeDeclarationsFromPCH, + ffi.Int32 displayDiagnostics, +); + +typedef _dart_clang_createIndex = ffi.Pointer Function( + int excludeDeclarationsFromPCH, + int displayDiagnostics, +); + +/// Same as clang_createTranslationUnit2, but returns the CXTranslationUnit instead of an error code. In case of an error this routine returns a NULL CXTranslationUnit, without further detailed error codes. +ffi.Pointer clang_createTranslationUnit( + ffi.Pointer CIdx, + ffi.Pointer ast_filename, +) { + return _clang_createTranslationUnit( + CIdx, + ast_filename, + ); +} + +final _dart_clang_createTranslationUnit _clang_createTranslationUnit = + _dylib.lookupFunction<_c_clang_createTranslationUnit, + _dart_clang_createTranslationUnit>('clang_createTranslationUnit'); + +typedef _c_clang_createTranslationUnit = ffi.Pointer + Function( + ffi.Pointer CIdx, + ffi.Pointer ast_filename, +); + +typedef _dart_clang_createTranslationUnit = ffi.Pointer + Function( + ffi.Pointer CIdx, + ffi.Pointer ast_filename, +); + +/// Create a translation unit from an AST file ( -emit-ast). +int clang_createTranslationUnit2( + ffi.Pointer CIdx, + ffi.Pointer ast_filename, + ffi.Pointer> out_TU, +) { + return _clang_createTranslationUnit2( + CIdx, + ast_filename, + out_TU, + ); +} + +final _dart_clang_createTranslationUnit2 _clang_createTranslationUnit2 = + _dylib.lookupFunction<_c_clang_createTranslationUnit2, + _dart_clang_createTranslationUnit2>('clang_createTranslationUnit2'); + +typedef _c_clang_createTranslationUnit2 = ffi.Int32 Function( + ffi.Pointer CIdx, + ffi.Pointer ast_filename, + ffi.Pointer> out_TU, +); + +typedef _dart_clang_createTranslationUnit2 = int Function( + ffi.Pointer CIdx, + ffi.Pointer ast_filename, + ffi.Pointer> out_TU, +); + +/// Return the CXTranslationUnit for a given source file and the provided command line arguments one would pass to the compiler. +ffi.Pointer clang_createTranslationUnitFromSourceFile( + ffi.Pointer CIdx, + ffi.Pointer source_filename, + int num_clang_command_line_args, + ffi.Pointer> clang_command_line_args, + int num_unsaved_files, + ffi.Pointer unsaved_files, +) { + return _clang_createTranslationUnitFromSourceFile( + CIdx, + source_filename, + num_clang_command_line_args, + clang_command_line_args, + num_unsaved_files, + unsaved_files, + ); +} + +final _dart_clang_createTranslationUnitFromSourceFile + _clang_createTranslationUnitFromSourceFile = _dylib.lookupFunction< + _c_clang_createTranslationUnitFromSourceFile, + _dart_clang_createTranslationUnitFromSourceFile>( + 'clang_createTranslationUnitFromSourceFile'); + +typedef _c_clang_createTranslationUnitFromSourceFile + = ffi.Pointer Function( + ffi.Pointer CIdx, + ffi.Pointer source_filename, + ffi.Int32 num_clang_command_line_args, + ffi.Pointer> clang_command_line_args, + ffi.Uint32 num_unsaved_files, + ffi.Pointer unsaved_files, +); + +typedef _dart_clang_createTranslationUnitFromSourceFile + = ffi.Pointer Function( + ffi.Pointer CIdx, + ffi.Pointer source_filename, + int num_clang_command_line_args, + ffi.Pointer> clang_command_line_args, + int num_unsaved_files, + ffi.Pointer unsaved_files, +); + +/// Returns a default set of code-completion options that can be passed to clang_codeCompleteAt(). +int clang_defaultCodeCompleteOptions() { + return _clang_defaultCodeCompleteOptions(); +} + +final _dart_clang_defaultCodeCompleteOptions _clang_defaultCodeCompleteOptions = + _dylib.lookupFunction<_c_clang_defaultCodeCompleteOptions, + _dart_clang_defaultCodeCompleteOptions>( + 'clang_defaultCodeCompleteOptions'); + +typedef _c_clang_defaultCodeCompleteOptions = ffi.Uint32 Function(); + +typedef _dart_clang_defaultCodeCompleteOptions = int Function(); + +/// Retrieve the set of display options most similar to the default behavior of the clang compiler. +int clang_defaultDiagnosticDisplayOptions() { + return _clang_defaultDiagnosticDisplayOptions(); +} + +final _dart_clang_defaultDiagnosticDisplayOptions + _clang_defaultDiagnosticDisplayOptions = _dylib.lookupFunction< + _c_clang_defaultDiagnosticDisplayOptions, + _dart_clang_defaultDiagnosticDisplayOptions>( + 'clang_defaultDiagnosticDisplayOptions'); + +typedef _c_clang_defaultDiagnosticDisplayOptions = ffi.Uint32 Function(); + +typedef _dart_clang_defaultDiagnosticDisplayOptions = int Function(); + +/// Returns the set of flags that is suitable for parsing a translation unit that is being edited. +int clang_defaultEditingTranslationUnitOptions() { + return _clang_defaultEditingTranslationUnitOptions(); +} + +final _dart_clang_defaultEditingTranslationUnitOptions + _clang_defaultEditingTranslationUnitOptions = _dylib.lookupFunction< + _c_clang_defaultEditingTranslationUnitOptions, + _dart_clang_defaultEditingTranslationUnitOptions>( + 'clang_defaultEditingTranslationUnitOptions'); + +typedef _c_clang_defaultEditingTranslationUnitOptions = ffi.Uint32 Function(); + +typedef _dart_clang_defaultEditingTranslationUnitOptions = int Function(); + +/// Returns the set of flags that is suitable for reparsing a translation unit. +int clang_defaultReparseOptions( + ffi.Pointer TU, +) { + return _clang_defaultReparseOptions( + TU, + ); +} + +final _dart_clang_defaultReparseOptions _clang_defaultReparseOptions = + _dylib.lookupFunction<_c_clang_defaultReparseOptions, + _dart_clang_defaultReparseOptions>('clang_defaultReparseOptions'); + +typedef _c_clang_defaultReparseOptions = ffi.Uint32 Function( + ffi.Pointer TU, +); + +typedef _dart_clang_defaultReparseOptions = int Function( + ffi.Pointer TU, +); + +/// Returns the set of flags that is suitable for saving a translation unit. +int clang_defaultSaveOptions( + ffi.Pointer TU, +) { + return _clang_defaultSaveOptions( + TU, + ); +} + +final _dart_clang_defaultSaveOptions _clang_defaultSaveOptions = + _dylib.lookupFunction<_c_clang_defaultSaveOptions, + _dart_clang_defaultSaveOptions>('clang_defaultSaveOptions'); + +typedef _c_clang_defaultSaveOptions = ffi.Uint32 Function( + ffi.Pointer TU, +); + +typedef _dart_clang_defaultSaveOptions = int Function( + ffi.Pointer TU, +); + +/// Disposes a CXCursorSet and releases its associated memory. +void clang_disposeCXCursorSet( + ffi.Pointer cset, +) { + return _clang_disposeCXCursorSet( + cset, + ); +} + +final _dart_clang_disposeCXCursorSet _clang_disposeCXCursorSet = + _dylib.lookupFunction<_c_clang_disposeCXCursorSet, + _dart_clang_disposeCXCursorSet>('clang_disposeCXCursorSet'); + +typedef _c_clang_disposeCXCursorSet = ffi.Void Function( + ffi.Pointer cset, +); + +typedef _dart_clang_disposeCXCursorSet = void Function( + ffi.Pointer cset, +); + +/// Free the memory associated with a CXPlatformAvailability structure. +void clang_disposeCXPlatformAvailability( + ffi.Pointer availability, +) { + return _clang_disposeCXPlatformAvailability( + availability, + ); +} + +final _dart_clang_disposeCXPlatformAvailability + _clang_disposeCXPlatformAvailability = _dylib.lookupFunction< + _c_clang_disposeCXPlatformAvailability, + _dart_clang_disposeCXPlatformAvailability>( + 'clang_disposeCXPlatformAvailability'); + +typedef _c_clang_disposeCXPlatformAvailability = ffi.Void Function( + ffi.Pointer availability, +); + +typedef _dart_clang_disposeCXPlatformAvailability = void Function( + ffi.Pointer availability, +); + +/// Free the given set of code-completion results. +void clang_disposeCodeCompleteResults( + ffi.Pointer Results, +) { + return _clang_disposeCodeCompleteResults( + Results, + ); +} + +final _dart_clang_disposeCodeCompleteResults _clang_disposeCodeCompleteResults = + _dylib.lookupFunction<_c_clang_disposeCodeCompleteResults, + _dart_clang_disposeCodeCompleteResults>( + 'clang_disposeCodeCompleteResults'); + +typedef _c_clang_disposeCodeCompleteResults = ffi.Void Function( + ffi.Pointer Results, +); + +typedef _dart_clang_disposeCodeCompleteResults = void Function( + ffi.Pointer Results, +); + +/// Destroy a diagnostic. +void clang_disposeDiagnostic( + ffi.Pointer Diagnostic, +) { + return _clang_disposeDiagnostic( + Diagnostic, + ); +} + +final _dart_clang_disposeDiagnostic _clang_disposeDiagnostic = _dylib + .lookupFunction<_c_clang_disposeDiagnostic, _dart_clang_disposeDiagnostic>( + 'clang_disposeDiagnostic'); + +typedef _c_clang_disposeDiagnostic = ffi.Void Function( + ffi.Pointer Diagnostic, +); + +typedef _dart_clang_disposeDiagnostic = void Function( + ffi.Pointer Diagnostic, +); + +/// Release a CXDiagnosticSet and all of its contained diagnostics. +void clang_disposeDiagnosticSet( + ffi.Pointer Diags, +) { + return _clang_disposeDiagnosticSet( + Diags, + ); +} + +final _dart_clang_disposeDiagnosticSet _clang_disposeDiagnosticSet = + _dylib.lookupFunction<_c_clang_disposeDiagnosticSet, + _dart_clang_disposeDiagnosticSet>('clang_disposeDiagnosticSet'); + +typedef _c_clang_disposeDiagnosticSet = ffi.Void Function( + ffi.Pointer Diags, +); + +typedef _dart_clang_disposeDiagnosticSet = void Function( + ffi.Pointer Diags, +); + +/// Destroy the given index. +void clang_disposeIndex( + ffi.Pointer index, +) { + return _clang_disposeIndex( + index, + ); +} + +final _dart_clang_disposeIndex _clang_disposeIndex = + _dylib.lookupFunction<_c_clang_disposeIndex, _dart_clang_disposeIndex>( + 'clang_disposeIndex'); + +typedef _c_clang_disposeIndex = ffi.Void Function( + ffi.Pointer index, +); + +typedef _dart_clang_disposeIndex = void Function( + ffi.Pointer index, +); + +/// Free the set of overridden cursors returned by clang_getOverriddenCursors(). +void clang_disposeOverriddenCursors( + ffi.Pointer overridden, +) { + return _clang_disposeOverriddenCursors( + overridden, + ); +} + +final _dart_clang_disposeOverriddenCursors _clang_disposeOverriddenCursors = + _dylib.lookupFunction<_c_clang_disposeOverriddenCursors, + _dart_clang_disposeOverriddenCursors>('clang_disposeOverriddenCursors'); + +typedef _c_clang_disposeOverriddenCursors = ffi.Void Function( + ffi.Pointer overridden, +); + +typedef _dart_clang_disposeOverriddenCursors = void Function( + ffi.Pointer overridden, +); + +/// Destroy the given CXSourceRangeList. +void clang_disposeSourceRangeList( + ffi.Pointer ranges, +) { + return _clang_disposeSourceRangeList( + ranges, + ); +} + +final _dart_clang_disposeSourceRangeList _clang_disposeSourceRangeList = + _dylib.lookupFunction<_c_clang_disposeSourceRangeList, + _dart_clang_disposeSourceRangeList>('clang_disposeSourceRangeList'); + +typedef _c_clang_disposeSourceRangeList = ffi.Void Function( + ffi.Pointer ranges, +); + +typedef _dart_clang_disposeSourceRangeList = void Function( + ffi.Pointer ranges, +); + +/// Free the given string set. +void clang_disposeStringSet( + ffi.Pointer set, +) { + return _clang_disposeStringSet( + set, + ); +} + +final _dart_clang_disposeStringSet _clang_disposeStringSet = _dylib + .lookupFunction<_c_clang_disposeStringSet, _dart_clang_disposeStringSet>( + 'clang_disposeStringSet'); + +typedef _c_clang_disposeStringSet = ffi.Void Function( + ffi.Pointer set, +); + +typedef _dart_clang_disposeStringSet = void Function( + ffi.Pointer set, +); + +void clang_disposeString_wrap( + ffi.Pointer string, +) { + return _clang_disposeString_wrap( + string, + ); +} + +final _dart_clang_disposeString_wrap _clang_disposeString_wrap = + _dylib.lookupFunction<_c_clang_disposeString_wrap, + _dart_clang_disposeString_wrap>('clang_disposeString_wrap'); + +typedef _c_clang_disposeString_wrap = ffi.Void Function( + ffi.Pointer string, +); + +typedef _dart_clang_disposeString_wrap = void Function( + ffi.Pointer string, +); + +/// Free the given set of tokens. +void clang_disposeTokens( + ffi.Pointer TU, + ffi.Pointer Tokens, + int NumTokens, +) { + return _clang_disposeTokens( + TU, + Tokens, + NumTokens, + ); +} + +final _dart_clang_disposeTokens _clang_disposeTokens = + _dylib.lookupFunction<_c_clang_disposeTokens, _dart_clang_disposeTokens>( + 'clang_disposeTokens'); + +typedef _c_clang_disposeTokens = ffi.Void Function( + ffi.Pointer TU, + ffi.Pointer Tokens, + ffi.Uint32 NumTokens, +); + +typedef _dart_clang_disposeTokens = void Function( + ffi.Pointer TU, + ffi.Pointer Tokens, + int NumTokens, +); + +/// Destroy the specified CXTranslationUnit object. +void clang_disposeTranslationUnit( + ffi.Pointer arg0, +) { + return _clang_disposeTranslationUnit( + arg0, + ); +} + +final _dart_clang_disposeTranslationUnit _clang_disposeTranslationUnit = + _dylib.lookupFunction<_c_clang_disposeTranslationUnit, + _dart_clang_disposeTranslationUnit>('clang_disposeTranslationUnit'); + +typedef _c_clang_disposeTranslationUnit = ffi.Void Function( + ffi.Pointer arg0, +); + +typedef _dart_clang_disposeTranslationUnit = void Function( + ffi.Pointer arg0, +); + +void clang_enableStackTraces() { + return _clang_enableStackTraces(); +} + +final _dart_clang_enableStackTraces _clang_enableStackTraces = _dylib + .lookupFunction<_c_clang_enableStackTraces, _dart_clang_enableStackTraces>( + 'clang_enableStackTraces'); + +typedef _c_clang_enableStackTraces = ffi.Void Function(); + +typedef _dart_clang_enableStackTraces = void Function(); + +void clang_executeOnThread( + ffi.Pointer> fn, + ffi.Pointer user_data, + int stack_size, +) { + return _clang_executeOnThread( + fn, + user_data, + stack_size, + ); +} + +final _dart_clang_executeOnThread _clang_executeOnThread = _dylib + .lookupFunction<_c_clang_executeOnThread, _dart_clang_executeOnThread>( + 'clang_executeOnThread'); + +typedef _c_clang_executeOnThread = ffi.Void Function( + ffi.Pointer> fn, + ffi.Pointer user_data, + ffi.Uint32 stack_size, +); + +typedef _dart_clang_executeOnThread = void Function( + ffi.Pointer> fn, + ffi.Pointer user_data, + int stack_size, +); + +ffi.Pointer clang_formatDiagnostic_wrap( + ffi.Pointer diag, + int opts, +) { + return _clang_formatDiagnostic_wrap( + diag, + opts, + ); +} + +final _dart_clang_formatDiagnostic_wrap _clang_formatDiagnostic_wrap = + _dylib.lookupFunction<_c_clang_formatDiagnostic_wrap, + _dart_clang_formatDiagnostic_wrap>('clang_formatDiagnostic_wrap'); + +typedef _c_clang_formatDiagnostic_wrap = ffi.Pointer Function( + ffi.Pointer diag, + ffi.Int32 opts, +); + +typedef _dart_clang_formatDiagnostic_wrap = ffi.Pointer Function( + ffi.Pointer diag, + int opts, +); + +/// Retrieve all ranges from all files that were skipped by the preprocessor. +ffi.Pointer clang_getAllSkippedRanges( + ffi.Pointer tu, +) { + return _clang_getAllSkippedRanges( + tu, + ); +} + +final _dart_clang_getAllSkippedRanges _clang_getAllSkippedRanges = + _dylib.lookupFunction<_c_clang_getAllSkippedRanges, + _dart_clang_getAllSkippedRanges>('clang_getAllSkippedRanges'); + +typedef _c_clang_getAllSkippedRanges = ffi.Pointer Function( + ffi.Pointer tu, +); + +typedef _dart_clang_getAllSkippedRanges = ffi.Pointer + Function( + ffi.Pointer tu, +); + +ffi.Pointer clang_getArgType_wrap( + ffi.Pointer cxtype, + int i, +) { + return _clang_getArgType_wrap( + cxtype, + i, + ); +} + +final _dart_clang_getArgType_wrap _clang_getArgType_wrap = _dylib + .lookupFunction<_c_clang_getArgType_wrap, _dart_clang_getArgType_wrap>( + 'clang_getArgType_wrap'); + +typedef _c_clang_getArgType_wrap = ffi.Pointer Function( + ffi.Pointer cxtype, + ffi.Uint32 i, +); + +typedef _dart_clang_getArgType_wrap = ffi.Pointer Function( + ffi.Pointer cxtype, + int i, +); + +ffi.Pointer clang_getArrayElementType_wrap( + ffi.Pointer cxtype, +) { + return _clang_getArrayElementType_wrap( + cxtype, + ); +} + +final _dart_clang_getArrayElementType_wrap _clang_getArrayElementType_wrap = + _dylib.lookupFunction<_c_clang_getArrayElementType_wrap, + _dart_clang_getArrayElementType_wrap>('clang_getArrayElementType_wrap'); + +typedef _c_clang_getArrayElementType_wrap = ffi.Pointer Function( + ffi.Pointer cxtype, +); + +typedef _dart_clang_getArrayElementType_wrap = ffi.Pointer Function( + ffi.Pointer cxtype, +); + +ffi.Pointer clang_getCString_wrap( + ffi.Pointer string, +) { + return _clang_getCString_wrap( + string, + ); +} + +final _dart_clang_getCString_wrap _clang_getCString_wrap = _dylib + .lookupFunction<_c_clang_getCString_wrap, _dart_clang_getCString_wrap>( + 'clang_getCString_wrap'); + +typedef _c_clang_getCString_wrap = ffi.Pointer Function( + ffi.Pointer string, +); + +typedef _dart_clang_getCString_wrap = ffi.Pointer Function( + ffi.Pointer string, +); + +ffi.Pointer clang_getCanonicalType_wrap( + ffi.Pointer typerefType, +) { + return _clang_getCanonicalType_wrap( + typerefType, + ); +} + +final _dart_clang_getCanonicalType_wrap _clang_getCanonicalType_wrap = + _dylib.lookupFunction<_c_clang_getCanonicalType_wrap, + _dart_clang_getCanonicalType_wrap>('clang_getCanonicalType_wrap'); + +typedef _c_clang_getCanonicalType_wrap = ffi.Pointer Function( + ffi.Pointer typerefType, +); + +typedef _dart_clang_getCanonicalType_wrap = ffi.Pointer Function( + ffi.Pointer typerefType, +); + +/// Retrieve the child diagnostics of a CXDiagnostic. +ffi.Pointer clang_getChildDiagnostics( + ffi.Pointer D, +) { + return _clang_getChildDiagnostics( + D, + ); +} + +final _dart_clang_getChildDiagnostics _clang_getChildDiagnostics = + _dylib.lookupFunction<_c_clang_getChildDiagnostics, + _dart_clang_getChildDiagnostics>('clang_getChildDiagnostics'); + +typedef _c_clang_getChildDiagnostics = ffi.Pointer Function( + ffi.Pointer D, +); + +typedef _dart_clang_getChildDiagnostics = ffi.Pointer Function( + ffi.Pointer D, +); + +/// Determine the availability of the entity that this code-completion string refers to. +int clang_getCompletionAvailability( + ffi.Pointer completion_string, +) { + return _clang_getCompletionAvailability( + completion_string, + ); +} + +final _dart_clang_getCompletionAvailability _clang_getCompletionAvailability = + _dylib.lookupFunction<_c_clang_getCompletionAvailability, + _dart_clang_getCompletionAvailability>( + 'clang_getCompletionAvailability'); + +typedef _c_clang_getCompletionAvailability = ffi.Int32 Function( + ffi.Pointer completion_string, +); + +typedef _dart_clang_getCompletionAvailability = int Function( + ffi.Pointer completion_string, +); + +/// Retrieve the completion string associated with a particular chunk within a completion string. +ffi.Pointer clang_getCompletionChunkCompletionString( + ffi.Pointer completion_string, + int chunk_number, +) { + return _clang_getCompletionChunkCompletionString( + completion_string, + chunk_number, + ); +} + +final _dart_clang_getCompletionChunkCompletionString + _clang_getCompletionChunkCompletionString = _dylib.lookupFunction< + _c_clang_getCompletionChunkCompletionString, + _dart_clang_getCompletionChunkCompletionString>( + 'clang_getCompletionChunkCompletionString'); + +typedef _c_clang_getCompletionChunkCompletionString = ffi.Pointer + Function( + ffi.Pointer completion_string, + ffi.Uint32 chunk_number, +); + +typedef _dart_clang_getCompletionChunkCompletionString = ffi.Pointer + Function( + ffi.Pointer completion_string, + int chunk_number, +); + +/// Determine the kind of a particular chunk within a completion string. +int clang_getCompletionChunkKind( + ffi.Pointer completion_string, + int chunk_number, +) { + return _clang_getCompletionChunkKind( + completion_string, + chunk_number, + ); +} + +final _dart_clang_getCompletionChunkKind _clang_getCompletionChunkKind = + _dylib.lookupFunction<_c_clang_getCompletionChunkKind, + _dart_clang_getCompletionChunkKind>('clang_getCompletionChunkKind'); + +typedef _c_clang_getCompletionChunkKind = ffi.Int32 Function( + ffi.Pointer completion_string, + ffi.Uint32 chunk_number, +); + +typedef _dart_clang_getCompletionChunkKind = int Function( + ffi.Pointer completion_string, + int chunk_number, +); + +/// Retrieve the number of annotations associated with the given completion string. +int clang_getCompletionNumAnnotations( + ffi.Pointer completion_string, +) { + return _clang_getCompletionNumAnnotations( + completion_string, + ); +} + +final _dart_clang_getCompletionNumAnnotations + _clang_getCompletionNumAnnotations = _dylib.lookupFunction< + _c_clang_getCompletionNumAnnotations, + _dart_clang_getCompletionNumAnnotations>( + 'clang_getCompletionNumAnnotations'); + +typedef _c_clang_getCompletionNumAnnotations = ffi.Uint32 Function( + ffi.Pointer completion_string, +); + +typedef _dart_clang_getCompletionNumAnnotations = int Function( + ffi.Pointer completion_string, +); + +/// Retrieve the number of fix-its for the given completion index. +int clang_getCompletionNumFixIts( + ffi.Pointer results, + int completion_index, +) { + return _clang_getCompletionNumFixIts( + results, + completion_index, + ); +} + +final _dart_clang_getCompletionNumFixIts _clang_getCompletionNumFixIts = + _dylib.lookupFunction<_c_clang_getCompletionNumFixIts, + _dart_clang_getCompletionNumFixIts>('clang_getCompletionNumFixIts'); + +typedef _c_clang_getCompletionNumFixIts = ffi.Uint32 Function( + ffi.Pointer results, + ffi.Uint32 completion_index, +); + +typedef _dart_clang_getCompletionNumFixIts = int Function( + ffi.Pointer results, + int completion_index, +); + +/// Determine the priority of this code completion. +int clang_getCompletionPriority( + ffi.Pointer completion_string, +) { + return _clang_getCompletionPriority( + completion_string, + ); +} + +final _dart_clang_getCompletionPriority _clang_getCompletionPriority = + _dylib.lookupFunction<_c_clang_getCompletionPriority, + _dart_clang_getCompletionPriority>('clang_getCompletionPriority'); + +typedef _c_clang_getCompletionPriority = ffi.Uint32 Function( + ffi.Pointer completion_string, +); + +typedef _dart_clang_getCompletionPriority = int Function( + ffi.Pointer completion_string, +); + +ffi.Pointer clang_getCursorKindSpelling_wrap( + int kind, +) { + return _clang_getCursorKindSpelling_wrap( + kind, + ); +} + +final _dart_clang_getCursorKindSpelling_wrap _clang_getCursorKindSpelling_wrap = + _dylib.lookupFunction<_c_clang_getCursorKindSpelling_wrap, + _dart_clang_getCursorKindSpelling_wrap>( + 'clang_getCursorKindSpelling_wrap'); + +typedef _c_clang_getCursorKindSpelling_wrap = ffi.Pointer Function( + ffi.Int32 kind, +); + +typedef _dart_clang_getCursorKindSpelling_wrap = ffi.Pointer Function( + int kind, +); + +int clang_getCursorKind_wrap( + ffi.Pointer cursor, +) { + return _clang_getCursorKind_wrap( + cursor, + ); +} + +final _dart_clang_getCursorKind_wrap _clang_getCursorKind_wrap = + _dylib.lookupFunction<_c_clang_getCursorKind_wrap, + _dart_clang_getCursorKind_wrap>('clang_getCursorKind_wrap'); + +typedef _c_clang_getCursorKind_wrap = ffi.Int32 Function( + ffi.Pointer cursor, +); + +typedef _dart_clang_getCursorKind_wrap = int Function( + ffi.Pointer cursor, +); + +ffi.Pointer clang_getCursorLocation_wrap( + ffi.Pointer cursor, +) { + return _clang_getCursorLocation_wrap( + cursor, + ); +} + +final _dart_clang_getCursorLocation_wrap _clang_getCursorLocation_wrap = + _dylib.lookupFunction<_c_clang_getCursorLocation_wrap, + _dart_clang_getCursorLocation_wrap>('clang_getCursorLocation_wrap'); + +typedef _c_clang_getCursorLocation_wrap = ffi.Pointer + Function( + ffi.Pointer cursor, +); + +typedef _dart_clang_getCursorLocation_wrap = ffi.Pointer + Function( + ffi.Pointer cursor, +); + +/// The name of parameter, struct, typedef. +ffi.Pointer clang_getCursorSpelling_wrap( + ffi.Pointer cursor, +) { + return _clang_getCursorSpelling_wrap( + cursor, + ); +} + +final _dart_clang_getCursorSpelling_wrap _clang_getCursorSpelling_wrap = + _dylib.lookupFunction<_c_clang_getCursorSpelling_wrap, + _dart_clang_getCursorSpelling_wrap>('clang_getCursorSpelling_wrap'); + +typedef _c_clang_getCursorSpelling_wrap = ffi.Pointer Function( + ffi.Pointer cursor, +); + +typedef _dart_clang_getCursorSpelling_wrap = ffi.Pointer Function( + ffi.Pointer cursor, +); + +ffi.Pointer clang_getCursorType_wrap( + ffi.Pointer cursor, +) { + return _clang_getCursorType_wrap( + cursor, + ); +} + +final _dart_clang_getCursorType_wrap _clang_getCursorType_wrap = + _dylib.lookupFunction<_c_clang_getCursorType_wrap, + _dart_clang_getCursorType_wrap>('clang_getCursorType_wrap'); + +typedef _c_clang_getCursorType_wrap = ffi.Pointer Function( + ffi.Pointer cursor, +); + +typedef _dart_clang_getCursorType_wrap = ffi.Pointer Function( + ffi.Pointer cursor, +); + +/// Retrieve a diagnostic associated with the given translation unit. +ffi.Pointer clang_getDiagnostic( + ffi.Pointer Unit, + int Index, +) { + return _clang_getDiagnostic( + Unit, + Index, + ); +} + +final _dart_clang_getDiagnostic _clang_getDiagnostic = + _dylib.lookupFunction<_c_clang_getDiagnostic, _dart_clang_getDiagnostic>( + 'clang_getDiagnostic'); + +typedef _c_clang_getDiagnostic = ffi.Pointer Function( + ffi.Pointer Unit, + ffi.Uint32 Index, +); + +typedef _dart_clang_getDiagnostic = ffi.Pointer Function( + ffi.Pointer Unit, + int Index, +); + +/// Retrieve the category number for this diagnostic. +int clang_getDiagnosticCategory( + ffi.Pointer arg0, +) { + return _clang_getDiagnosticCategory( + arg0, + ); +} + +final _dart_clang_getDiagnosticCategory _clang_getDiagnosticCategory = + _dylib.lookupFunction<_c_clang_getDiagnosticCategory, + _dart_clang_getDiagnosticCategory>('clang_getDiagnosticCategory'); + +typedef _c_clang_getDiagnosticCategory = ffi.Uint32 Function( + ffi.Pointer arg0, +); + +typedef _dart_clang_getDiagnosticCategory = int Function( + ffi.Pointer arg0, +); + +/// Retrieve a diagnostic associated with the given CXDiagnosticSet. +ffi.Pointer clang_getDiagnosticInSet( + ffi.Pointer Diags, + int Index, +) { + return _clang_getDiagnosticInSet( + Diags, + Index, + ); +} + +final _dart_clang_getDiagnosticInSet _clang_getDiagnosticInSet = + _dylib.lookupFunction<_c_clang_getDiagnosticInSet, + _dart_clang_getDiagnosticInSet>('clang_getDiagnosticInSet'); + +typedef _c_clang_getDiagnosticInSet = ffi.Pointer Function( + ffi.Pointer Diags, + ffi.Uint32 Index, +); + +typedef _dart_clang_getDiagnosticInSet = ffi.Pointer Function( + ffi.Pointer Diags, + int Index, +); + +/// Determine the number of fix-it hints associated with the given diagnostic. +int clang_getDiagnosticNumFixIts( + ffi.Pointer Diagnostic, +) { + return _clang_getDiagnosticNumFixIts( + Diagnostic, + ); +} + +final _dart_clang_getDiagnosticNumFixIts _clang_getDiagnosticNumFixIts = + _dylib.lookupFunction<_c_clang_getDiagnosticNumFixIts, + _dart_clang_getDiagnosticNumFixIts>('clang_getDiagnosticNumFixIts'); + +typedef _c_clang_getDiagnosticNumFixIts = ffi.Uint32 Function( + ffi.Pointer Diagnostic, +); + +typedef _dart_clang_getDiagnosticNumFixIts = int Function( + ffi.Pointer Diagnostic, +); + +/// Determine the number of source ranges associated with the given diagnostic. +int clang_getDiagnosticNumRanges( + ffi.Pointer arg0, +) { + return _clang_getDiagnosticNumRanges( + arg0, + ); +} + +final _dart_clang_getDiagnosticNumRanges _clang_getDiagnosticNumRanges = + _dylib.lookupFunction<_c_clang_getDiagnosticNumRanges, + _dart_clang_getDiagnosticNumRanges>('clang_getDiagnosticNumRanges'); + +typedef _c_clang_getDiagnosticNumRanges = ffi.Uint32 Function( + ffi.Pointer arg0, +); + +typedef _dart_clang_getDiagnosticNumRanges = int Function( + ffi.Pointer arg0, +); + +/// Retrieve the complete set of diagnostics associated with a translation unit. +ffi.Pointer clang_getDiagnosticSetFromTU( + ffi.Pointer Unit, +) { + return _clang_getDiagnosticSetFromTU( + Unit, + ); +} + +final _dart_clang_getDiagnosticSetFromTU _clang_getDiagnosticSetFromTU = + _dylib.lookupFunction<_c_clang_getDiagnosticSetFromTU, + _dart_clang_getDiagnosticSetFromTU>('clang_getDiagnosticSetFromTU'); + +typedef _c_clang_getDiagnosticSetFromTU = ffi.Pointer Function( + ffi.Pointer Unit, +); + +typedef _dart_clang_getDiagnosticSetFromTU = ffi.Pointer Function( + ffi.Pointer Unit, +); + +/// Determine the severity of the given diagnostic. +int clang_getDiagnosticSeverity( + ffi.Pointer arg0, +) { + return _clang_getDiagnosticSeverity( + arg0, + ); +} + +final _dart_clang_getDiagnosticSeverity _clang_getDiagnosticSeverity = + _dylib.lookupFunction<_c_clang_getDiagnosticSeverity, + _dart_clang_getDiagnosticSeverity>('clang_getDiagnosticSeverity'); + +typedef _c_clang_getDiagnosticSeverity = ffi.Int32 Function( + ffi.Pointer arg0, +); + +typedef _dart_clang_getDiagnosticSeverity = int Function( + ffi.Pointer arg0, +); + +int clang_getEnumConstantDeclValue_wrap( + ffi.Pointer cursor, +) { + return _clang_getEnumConstantDeclValue_wrap( + cursor, + ); +} + +final _dart_clang_getEnumConstantDeclValue_wrap + _clang_getEnumConstantDeclValue_wrap = _dylib.lookupFunction< + _c_clang_getEnumConstantDeclValue_wrap, + _dart_clang_getEnumConstantDeclValue_wrap>( + 'clang_getEnumConstantDeclValue_wrap'); + +typedef _c_clang_getEnumConstantDeclValue_wrap = ffi.Int64 Function( + ffi.Pointer cursor, +); + +typedef _dart_clang_getEnumConstantDeclValue_wrap = int Function( + ffi.Pointer cursor, +); + +/// Retrieve a file handle within the given translation unit. +ffi.Pointer clang_getFile( + ffi.Pointer tu, + ffi.Pointer file_name, +) { + return _clang_getFile( + tu, + file_name, + ); +} + +final _dart_clang_getFile _clang_getFile = _dylib + .lookupFunction<_c_clang_getFile, _dart_clang_getFile>('clang_getFile'); + +typedef _c_clang_getFile = ffi.Pointer Function( + ffi.Pointer tu, + ffi.Pointer file_name, +); + +typedef _dart_clang_getFile = ffi.Pointer Function( + ffi.Pointer tu, + ffi.Pointer file_name, +); + +/// Retrieve the buffer associated with the given file. +ffi.Pointer clang_getFileContents( + ffi.Pointer tu, + ffi.Pointer file, + ffi.Pointer size, +) { + return _clang_getFileContents( + tu, + file, + size, + ); +} + +final _dart_clang_getFileContents _clang_getFileContents = _dylib + .lookupFunction<_c_clang_getFileContents, _dart_clang_getFileContents>( + 'clang_getFileContents'); + +typedef _c_clang_getFileContents = ffi.Pointer Function( + ffi.Pointer tu, + ffi.Pointer file, + ffi.Pointer size, +); + +typedef _dart_clang_getFileContents = ffi.Pointer Function( + ffi.Pointer tu, + ffi.Pointer file, + ffi.Pointer size, +); + +void clang_getFileLocation_wrap( + ffi.Pointer location, + ffi.Pointer> file, + ffi.Pointer line, + ffi.Pointer column, + ffi.Pointer offset, +) { + return _clang_getFileLocation_wrap( + location, + file, + line, + column, + offset, + ); +} + +final _dart_clang_getFileLocation_wrap _clang_getFileLocation_wrap = + _dylib.lookupFunction<_c_clang_getFileLocation_wrap, + _dart_clang_getFileLocation_wrap>('clang_getFileLocation_wrap'); + +typedef _c_clang_getFileLocation_wrap = ffi.Void Function( + ffi.Pointer location, + ffi.Pointer> file, + ffi.Pointer line, + ffi.Pointer column, + ffi.Pointer offset, +); + +typedef _dart_clang_getFileLocation_wrap = void Function( + ffi.Pointer location, + ffi.Pointer> file, + ffi.Pointer line, + ffi.Pointer column, + ffi.Pointer offset, +); + +ffi.Pointer clang_getFileName_wrap( + ffi.Pointer SFile, +) { + return _clang_getFileName_wrap( + SFile, + ); +} + +final _dart_clang_getFileName_wrap _clang_getFileName_wrap = _dylib + .lookupFunction<_c_clang_getFileName_wrap, _dart_clang_getFileName_wrap>( + 'clang_getFileName_wrap'); + +typedef _c_clang_getFileName_wrap = ffi.Pointer Function( + ffi.Pointer SFile, +); + +typedef _dart_clang_getFileName_wrap = ffi.Pointer Function( + ffi.Pointer SFile, +); + +/// Retrieve the last modification time of the given file. +int clang_getFileTime( + ffi.Pointer SFile, +) { + return _clang_getFileTime( + SFile, + ); +} + +final _dart_clang_getFileTime _clang_getFileTime = + _dylib.lookupFunction<_c_clang_getFileTime, _dart_clang_getFileTime>( + 'clang_getFileTime'); + +typedef _c_clang_getFileTime = ffi.Int64 Function( + ffi.Pointer SFile, +); + +typedef _dart_clang_getFileTime = int Function( + ffi.Pointer SFile, +); + +/// Retrieve the unique ID for the given file. +int clang_getFileUniqueID( + ffi.Pointer file, + ffi.Pointer outID, +) { + return _clang_getFileUniqueID( + file, + outID, + ); +} + +final _dart_clang_getFileUniqueID _clang_getFileUniqueID = _dylib + .lookupFunction<_c_clang_getFileUniqueID, _dart_clang_getFileUniqueID>( + 'clang_getFileUniqueID'); + +typedef _c_clang_getFileUniqueID = ffi.Int32 Function( + ffi.Pointer file, + ffi.Pointer outID, +); + +typedef _dart_clang_getFileUniqueID = int Function( + ffi.Pointer file, + ffi.Pointer outID, +); + +/// Visit the set of preprocessor inclusions in a translation unit. The visitor function is called with the provided data for every included file. This does not include headers included by the PCH file (unless one is inspecting the inclusions in the PCH file itself). +void clang_getInclusions( + ffi.Pointer tu, + ffi.Pointer> visitor, + ffi.Pointer client_data, +) { + return _clang_getInclusions( + tu, + visitor, + client_data, + ); +} + +final _dart_clang_getInclusions _clang_getInclusions = + _dylib.lookupFunction<_c_clang_getInclusions, _dart_clang_getInclusions>( + 'clang_getInclusions'); + +typedef _c_clang_getInclusions = ffi.Void Function( + ffi.Pointer tu, + ffi.Pointer> visitor, + ffi.Pointer client_data, +); + +typedef _dart_clang_getInclusions = void Function( + ffi.Pointer tu, + ffi.Pointer> visitor, + ffi.Pointer client_data, +); + +/// Given a CXFile header file, return the module that contains it, if one exists. +ffi.Pointer clang_getModuleForFile( + ffi.Pointer arg0, + ffi.Pointer arg1, +) { + return _clang_getModuleForFile( + arg0, + arg1, + ); +} + +final _dart_clang_getModuleForFile _clang_getModuleForFile = _dylib + .lookupFunction<_c_clang_getModuleForFile, _dart_clang_getModuleForFile>( + 'clang_getModuleForFile'); + +typedef _c_clang_getModuleForFile = ffi.Pointer Function( + ffi.Pointer arg0, + ffi.Pointer arg1, +); + +typedef _dart_clang_getModuleForFile = ffi.Pointer Function( + ffi.Pointer arg0, + ffi.Pointer arg1, +); + +int clang_getNumArgTypes_wrap( + ffi.Pointer cxtype, +) { + return _clang_getNumArgTypes_wrap( + cxtype, + ); +} + +final _dart_clang_getNumArgTypes_wrap _clang_getNumArgTypes_wrap = + _dylib.lookupFunction<_c_clang_getNumArgTypes_wrap, + _dart_clang_getNumArgTypes_wrap>('clang_getNumArgTypes_wrap'); + +typedef _c_clang_getNumArgTypes_wrap = ffi.Int32 Function( + ffi.Pointer cxtype, +); + +typedef _dart_clang_getNumArgTypes_wrap = int Function( + ffi.Pointer cxtype, +); + +/// Retrieve the number of chunks in the given code-completion string. +int clang_getNumCompletionChunks( + ffi.Pointer completion_string, +) { + return _clang_getNumCompletionChunks( + completion_string, + ); +} + +final _dart_clang_getNumCompletionChunks _clang_getNumCompletionChunks = + _dylib.lookupFunction<_c_clang_getNumCompletionChunks, + _dart_clang_getNumCompletionChunks>('clang_getNumCompletionChunks'); + +typedef _c_clang_getNumCompletionChunks = ffi.Uint32 Function( + ffi.Pointer completion_string, +); + +typedef _dart_clang_getNumCompletionChunks = int Function( + ffi.Pointer completion_string, +); + +/// Determine the number of diagnostics produced for the given translation unit. +int clang_getNumDiagnostics( + ffi.Pointer Unit, +) { + return _clang_getNumDiagnostics( + Unit, + ); +} + +final _dart_clang_getNumDiagnostics _clang_getNumDiagnostics = _dylib + .lookupFunction<_c_clang_getNumDiagnostics, _dart_clang_getNumDiagnostics>( + 'clang_getNumDiagnostics'); + +typedef _c_clang_getNumDiagnostics = ffi.Uint32 Function( + ffi.Pointer Unit, +); + +typedef _dart_clang_getNumDiagnostics = int Function( + ffi.Pointer Unit, +); + +/// Determine the number of diagnostics in a CXDiagnosticSet. +int clang_getNumDiagnosticsInSet( + ffi.Pointer Diags, +) { + return _clang_getNumDiagnosticsInSet( + Diags, + ); +} + +final _dart_clang_getNumDiagnosticsInSet _clang_getNumDiagnosticsInSet = + _dylib.lookupFunction<_c_clang_getNumDiagnosticsInSet, + _dart_clang_getNumDiagnosticsInSet>('clang_getNumDiagnosticsInSet'); + +typedef _c_clang_getNumDiagnosticsInSet = ffi.Uint32 Function( + ffi.Pointer Diags, +); + +typedef _dart_clang_getNumDiagnosticsInSet = int Function( + ffi.Pointer Diags, +); + +int clang_getNumElements_wrap( + ffi.Pointer cxtype, +) { + return _clang_getNumElements_wrap( + cxtype, + ); +} + +final _dart_clang_getNumElements_wrap _clang_getNumElements_wrap = + _dylib.lookupFunction<_c_clang_getNumElements_wrap, + _dart_clang_getNumElements_wrap>('clang_getNumElements_wrap'); + +typedef _c_clang_getNumElements_wrap = ffi.Uint64 Function( + ffi.Pointer cxtype, +); + +typedef _dart_clang_getNumElements_wrap = int Function( + ffi.Pointer cxtype, +); + +ffi.Pointer clang_getPointeeType_wrap( + ffi.Pointer pointerType, +) { + return _clang_getPointeeType_wrap( + pointerType, + ); +} + +final _dart_clang_getPointeeType_wrap _clang_getPointeeType_wrap = + _dylib.lookupFunction<_c_clang_getPointeeType_wrap, + _dart_clang_getPointeeType_wrap>('clang_getPointeeType_wrap'); + +typedef _c_clang_getPointeeType_wrap = ffi.Pointer Function( + ffi.Pointer pointerType, +); + +typedef _dart_clang_getPointeeType_wrap = ffi.Pointer Function( + ffi.Pointer pointerType, +); + +/// Retrieve a remapping. +ffi.Pointer clang_getRemappings( + ffi.Pointer path, +) { + return _clang_getRemappings( + path, + ); +} + +final _dart_clang_getRemappings _clang_getRemappings = + _dylib.lookupFunction<_c_clang_getRemappings, _dart_clang_getRemappings>( + 'clang_getRemappings'); + +typedef _c_clang_getRemappings = ffi.Pointer Function( + ffi.Pointer path, +); + +typedef _dart_clang_getRemappings = ffi.Pointer Function( + ffi.Pointer path, +); + +/// Retrieve a remapping. +ffi.Pointer clang_getRemappingsFromFileList( + ffi.Pointer> filePaths, + int numFiles, +) { + return _clang_getRemappingsFromFileList( + filePaths, + numFiles, + ); +} + +final _dart_clang_getRemappingsFromFileList _clang_getRemappingsFromFileList = + _dylib.lookupFunction<_c_clang_getRemappingsFromFileList, + _dart_clang_getRemappingsFromFileList>( + 'clang_getRemappingsFromFileList'); + +typedef _c_clang_getRemappingsFromFileList = ffi.Pointer Function( + ffi.Pointer> filePaths, + ffi.Uint32 numFiles, +); + +typedef _dart_clang_getRemappingsFromFileList = ffi.Pointer Function( + ffi.Pointer> filePaths, + int numFiles, +); + +ffi.Pointer clang_getResultType_wrap( + ffi.Pointer functionType, +) { + return _clang_getResultType_wrap( + functionType, + ); +} + +final _dart_clang_getResultType_wrap _clang_getResultType_wrap = + _dylib.lookupFunction<_c_clang_getResultType_wrap, + _dart_clang_getResultType_wrap>('clang_getResultType_wrap'); + +typedef _c_clang_getResultType_wrap = ffi.Pointer Function( + ffi.Pointer functionType, +); + +typedef _dart_clang_getResultType_wrap = ffi.Pointer Function( + ffi.Pointer functionType, +); + +/// Retrieve all ranges that were skipped by the preprocessor. +ffi.Pointer clang_getSkippedRanges( + ffi.Pointer tu, + ffi.Pointer file, +) { + return _clang_getSkippedRanges( + tu, + file, + ); +} + +final _dart_clang_getSkippedRanges _clang_getSkippedRanges = _dylib + .lookupFunction<_c_clang_getSkippedRanges, _dart_clang_getSkippedRanges>( + 'clang_getSkippedRanges'); + +typedef _c_clang_getSkippedRanges = ffi.Pointer Function( + ffi.Pointer tu, + ffi.Pointer file, +); + +typedef _dart_clang_getSkippedRanges = ffi.Pointer Function( + ffi.Pointer tu, + ffi.Pointer file, +); + +/// Returns the human-readable null-terminated C string that represents the name of the memory category. This string should never be freed. +ffi.Pointer clang_getTUResourceUsageName( + int kind, +) { + return _clang_getTUResourceUsageName( + kind, + ); +} + +final _dart_clang_getTUResourceUsageName _clang_getTUResourceUsageName = + _dylib.lookupFunction<_c_clang_getTUResourceUsageName, + _dart_clang_getTUResourceUsageName>('clang_getTUResourceUsageName'); + +typedef _c_clang_getTUResourceUsageName = ffi.Pointer Function( + ffi.Int32 kind, +); + +typedef _dart_clang_getTUResourceUsageName = ffi.Pointer Function( + int kind, +); + +ffi.Pointer clang_getTranslationUnitCursor_wrap( + ffi.Pointer tu, +) { + return _clang_getTranslationUnitCursor_wrap( + tu, + ); +} + +final _dart_clang_getTranslationUnitCursor_wrap + _clang_getTranslationUnitCursor_wrap = _dylib.lookupFunction< + _c_clang_getTranslationUnitCursor_wrap, + _dart_clang_getTranslationUnitCursor_wrap>( + 'clang_getTranslationUnitCursor_wrap'); + +typedef _c_clang_getTranslationUnitCursor_wrap = ffi.Pointer Function( + ffi.Pointer tu, +); + +typedef _dart_clang_getTranslationUnitCursor_wrap = ffi.Pointer + Function( + ffi.Pointer tu, +); + +/// Get target information for this translation unit. +ffi.Pointer clang_getTranslationUnitTargetInfo( + ffi.Pointer CTUnit, +) { + return _clang_getTranslationUnitTargetInfo( + CTUnit, + ); +} + +final _dart_clang_getTranslationUnitTargetInfo + _clang_getTranslationUnitTargetInfo = _dylib.lookupFunction< + _c_clang_getTranslationUnitTargetInfo, + _dart_clang_getTranslationUnitTargetInfo>( + 'clang_getTranslationUnitTargetInfo'); + +typedef _c_clang_getTranslationUnitTargetInfo = ffi.Pointer + Function( + ffi.Pointer CTUnit, +); + +typedef _dart_clang_getTranslationUnitTargetInfo = ffi.Pointer + Function( + ffi.Pointer CTUnit, +); + +ffi.Pointer clang_getTypeDeclaration_wrap( + ffi.Pointer cxtype, +) { + return _clang_getTypeDeclaration_wrap( + cxtype, + ); +} + +final _dart_clang_getTypeDeclaration_wrap _clang_getTypeDeclaration_wrap = + _dylib.lookupFunction<_c_clang_getTypeDeclaration_wrap, + _dart_clang_getTypeDeclaration_wrap>('clang_getTypeDeclaration_wrap'); + +typedef _c_clang_getTypeDeclaration_wrap = ffi.Pointer Function( + ffi.Pointer cxtype, +); + +typedef _dart_clang_getTypeDeclaration_wrap = ffi.Pointer Function( + ffi.Pointer cxtype, +); + +ffi.Pointer clang_getTypeKindSpelling_wrap( + int typeKind, +) { + return _clang_getTypeKindSpelling_wrap( + typeKind, + ); +} + +final _dart_clang_getTypeKindSpelling_wrap _clang_getTypeKindSpelling_wrap = + _dylib.lookupFunction<_c_clang_getTypeKindSpelling_wrap, + _dart_clang_getTypeKindSpelling_wrap>('clang_getTypeKindSpelling_wrap'); + +typedef _c_clang_getTypeKindSpelling_wrap = ffi.Pointer Function( + ffi.Int32 typeKind, +); + +typedef _dart_clang_getTypeKindSpelling_wrap = ffi.Pointer Function( + int typeKind, +); + +ffi.Pointer clang_getTypeSpelling_wrap( + ffi.Pointer type, +) { + return _clang_getTypeSpelling_wrap( + type, + ); +} + +final _dart_clang_getTypeSpelling_wrap _clang_getTypeSpelling_wrap = + _dylib.lookupFunction<_c_clang_getTypeSpelling_wrap, + _dart_clang_getTypeSpelling_wrap>('clang_getTypeSpelling_wrap'); + +typedef _c_clang_getTypeSpelling_wrap = ffi.Pointer Function( + ffi.Pointer type, +); + +typedef _dart_clang_getTypeSpelling_wrap = ffi.Pointer Function( + ffi.Pointer type, +); + +ffi.Pointer clang_getTypedefDeclUnderlyingType_wrap( + ffi.Pointer cxcursor, +) { + return _clang_getTypedefDeclUnderlyingType_wrap( + cxcursor, + ); +} + +final _dart_clang_getTypedefDeclUnderlyingType_wrap + _clang_getTypedefDeclUnderlyingType_wrap = _dylib.lookupFunction< + _c_clang_getTypedefDeclUnderlyingType_wrap, + _dart_clang_getTypedefDeclUnderlyingType_wrap>( + 'clang_getTypedefDeclUnderlyingType_wrap'); + +typedef _c_clang_getTypedefDeclUnderlyingType_wrap = ffi.Pointer + Function( + ffi.Pointer cxcursor, +); + +typedef _dart_clang_getTypedefDeclUnderlyingType_wrap = ffi.Pointer + Function( + ffi.Pointer cxcursor, +); + +/// Index the given source file and the translation unit corresponding to that file via callbacks implemented through #IndexerCallbacks. +int clang_indexSourceFile( + ffi.Pointer arg0, + ffi.Pointer client_data, + ffi.Pointer index_callbacks, + int index_callbacks_size, + int index_options, + ffi.Pointer source_filename, + ffi.Pointer> command_line_args, + int num_command_line_args, + ffi.Pointer unsaved_files, + int num_unsaved_files, + ffi.Pointer> out_TU, + int TU_options, +) { + return _clang_indexSourceFile( + arg0, + client_data, + index_callbacks, + index_callbacks_size, + index_options, + source_filename, + command_line_args, + num_command_line_args, + unsaved_files, + num_unsaved_files, + out_TU, + TU_options, + ); +} + +final _dart_clang_indexSourceFile _clang_indexSourceFile = _dylib + .lookupFunction<_c_clang_indexSourceFile, _dart_clang_indexSourceFile>( + 'clang_indexSourceFile'); + +typedef _c_clang_indexSourceFile = ffi.Int32 Function( + ffi.Pointer arg0, + ffi.Pointer client_data, + ffi.Pointer index_callbacks, + ffi.Uint32 index_callbacks_size, + ffi.Uint32 index_options, + ffi.Pointer source_filename, + ffi.Pointer> command_line_args, + ffi.Int32 num_command_line_args, + ffi.Pointer unsaved_files, + ffi.Uint32 num_unsaved_files, + ffi.Pointer> out_TU, + ffi.Uint32 TU_options, +); + +typedef _dart_clang_indexSourceFile = int Function( + ffi.Pointer arg0, + ffi.Pointer client_data, + ffi.Pointer index_callbacks, + int index_callbacks_size, + int index_options, + ffi.Pointer source_filename, + ffi.Pointer> command_line_args, + int num_command_line_args, + ffi.Pointer unsaved_files, + int num_unsaved_files, + ffi.Pointer> out_TU, + int TU_options, +); + +/// Same as clang_indexSourceFile but requires a full command line for command_line_args including argv[0]. This is useful if the standard library paths are relative to the binary. +int clang_indexSourceFileFullArgv( + ffi.Pointer arg0, + ffi.Pointer client_data, + ffi.Pointer index_callbacks, + int index_callbacks_size, + int index_options, + ffi.Pointer source_filename, + ffi.Pointer> command_line_args, + int num_command_line_args, + ffi.Pointer unsaved_files, + int num_unsaved_files, + ffi.Pointer> out_TU, + int TU_options, +) { + return _clang_indexSourceFileFullArgv( + arg0, + client_data, + index_callbacks, + index_callbacks_size, + index_options, + source_filename, + command_line_args, + num_command_line_args, + unsaved_files, + num_unsaved_files, + out_TU, + TU_options, + ); +} + +final _dart_clang_indexSourceFileFullArgv _clang_indexSourceFileFullArgv = + _dylib.lookupFunction<_c_clang_indexSourceFileFullArgv, + _dart_clang_indexSourceFileFullArgv>('clang_indexSourceFileFullArgv'); + +typedef _c_clang_indexSourceFileFullArgv = ffi.Int32 Function( + ffi.Pointer arg0, + ffi.Pointer client_data, + ffi.Pointer index_callbacks, + ffi.Uint32 index_callbacks_size, + ffi.Uint32 index_options, + ffi.Pointer source_filename, + ffi.Pointer> command_line_args, + ffi.Int32 num_command_line_args, + ffi.Pointer unsaved_files, + ffi.Uint32 num_unsaved_files, + ffi.Pointer> out_TU, + ffi.Uint32 TU_options, +); + +typedef _dart_clang_indexSourceFileFullArgv = int Function( + ffi.Pointer arg0, + ffi.Pointer client_data, + ffi.Pointer index_callbacks, + int index_callbacks_size, + int index_options, + ffi.Pointer source_filename, + ffi.Pointer> command_line_args, + int num_command_line_args, + ffi.Pointer unsaved_files, + int num_unsaved_files, + ffi.Pointer> out_TU, + int TU_options, +); + +/// Index the given translation unit via callbacks implemented through #IndexerCallbacks. +int clang_indexTranslationUnit( + ffi.Pointer arg0, + ffi.Pointer client_data, + ffi.Pointer index_callbacks, + int index_callbacks_size, + int index_options, + ffi.Pointer arg5, +) { + return _clang_indexTranslationUnit( + arg0, + client_data, + index_callbacks, + index_callbacks_size, + index_options, + arg5, + ); +} + +final _dart_clang_indexTranslationUnit _clang_indexTranslationUnit = + _dylib.lookupFunction<_c_clang_indexTranslationUnit, + _dart_clang_indexTranslationUnit>('clang_indexTranslationUnit'); + +typedef _c_clang_indexTranslationUnit = ffi.Int32 Function( + ffi.Pointer arg0, + ffi.Pointer client_data, + ffi.Pointer index_callbacks, + ffi.Uint32 index_callbacks_size, + ffi.Uint32 index_options, + ffi.Pointer arg5, +); + +typedef _dart_clang_indexTranslationUnit = int Function( + ffi.Pointer arg0, + ffi.Pointer client_data, + ffi.Pointer index_callbacks, + int index_callbacks_size, + int index_options, + ffi.Pointer arg5, +); + +ffi.Pointer clang_index_getCXXClassDeclInfo( + ffi.Pointer arg0, +) { + return _clang_index_getCXXClassDeclInfo( + arg0, + ); +} + +final _dart_clang_index_getCXXClassDeclInfo _clang_index_getCXXClassDeclInfo = + _dylib.lookupFunction<_c_clang_index_getCXXClassDeclInfo, + _dart_clang_index_getCXXClassDeclInfo>( + 'clang_index_getCXXClassDeclInfo'); + +typedef _c_clang_index_getCXXClassDeclInfo = ffi.Pointer + Function( + ffi.Pointer arg0, +); + +typedef _dart_clang_index_getCXXClassDeclInfo + = ffi.Pointer Function( + ffi.Pointer arg0, +); + +/// For retrieving a custom CXIdxClientContainer attached to a container. +ffi.Pointer clang_index_getClientContainer( + ffi.Pointer arg0, +) { + return _clang_index_getClientContainer( + arg0, + ); +} + +final _dart_clang_index_getClientContainer _clang_index_getClientContainer = + _dylib.lookupFunction<_c_clang_index_getClientContainer, + _dart_clang_index_getClientContainer>('clang_index_getClientContainer'); + +typedef _c_clang_index_getClientContainer = ffi.Pointer Function( + ffi.Pointer arg0, +); + +typedef _dart_clang_index_getClientContainer = ffi.Pointer Function( + ffi.Pointer arg0, +); + +/// For retrieving a custom CXIdxClientEntity attached to an entity. +ffi.Pointer clang_index_getClientEntity( + ffi.Pointer arg0, +) { + return _clang_index_getClientEntity( + arg0, + ); +} + +final _dart_clang_index_getClientEntity _clang_index_getClientEntity = + _dylib.lookupFunction<_c_clang_index_getClientEntity, + _dart_clang_index_getClientEntity>('clang_index_getClientEntity'); + +typedef _c_clang_index_getClientEntity = ffi.Pointer Function( + ffi.Pointer arg0, +); + +typedef _dart_clang_index_getClientEntity = ffi.Pointer Function( + ffi.Pointer arg0, +); + +ffi.Pointer + clang_index_getIBOutletCollectionAttrInfo( + ffi.Pointer arg0, +) { + return _clang_index_getIBOutletCollectionAttrInfo( + arg0, + ); +} + +final _dart_clang_index_getIBOutletCollectionAttrInfo + _clang_index_getIBOutletCollectionAttrInfo = _dylib.lookupFunction< + _c_clang_index_getIBOutletCollectionAttrInfo, + _dart_clang_index_getIBOutletCollectionAttrInfo>( + 'clang_index_getIBOutletCollectionAttrInfo'); + +typedef _c_clang_index_getIBOutletCollectionAttrInfo + = ffi.Pointer Function( + ffi.Pointer arg0, +); + +typedef _dart_clang_index_getIBOutletCollectionAttrInfo + = ffi.Pointer Function( + ffi.Pointer arg0, +); + +ffi.Pointer clang_index_getObjCCategoryDeclInfo( + ffi.Pointer arg0, +) { + return _clang_index_getObjCCategoryDeclInfo( + arg0, + ); +} + +final _dart_clang_index_getObjCCategoryDeclInfo + _clang_index_getObjCCategoryDeclInfo = _dylib.lookupFunction< + _c_clang_index_getObjCCategoryDeclInfo, + _dart_clang_index_getObjCCategoryDeclInfo>( + 'clang_index_getObjCCategoryDeclInfo'); + +typedef _c_clang_index_getObjCCategoryDeclInfo + = ffi.Pointer Function( + ffi.Pointer arg0, +); + +typedef _dart_clang_index_getObjCCategoryDeclInfo + = ffi.Pointer Function( + ffi.Pointer arg0, +); + +ffi.Pointer clang_index_getObjCContainerDeclInfo( + ffi.Pointer arg0, +) { + return _clang_index_getObjCContainerDeclInfo( + arg0, + ); +} + +final _dart_clang_index_getObjCContainerDeclInfo + _clang_index_getObjCContainerDeclInfo = _dylib.lookupFunction< + _c_clang_index_getObjCContainerDeclInfo, + _dart_clang_index_getObjCContainerDeclInfo>( + 'clang_index_getObjCContainerDeclInfo'); + +typedef _c_clang_index_getObjCContainerDeclInfo + = ffi.Pointer Function( + ffi.Pointer arg0, +); + +typedef _dart_clang_index_getObjCContainerDeclInfo + = ffi.Pointer Function( + ffi.Pointer arg0, +); + +ffi.Pointer clang_index_getObjCInterfaceDeclInfo( + ffi.Pointer arg0, +) { + return _clang_index_getObjCInterfaceDeclInfo( + arg0, + ); +} + +final _dart_clang_index_getObjCInterfaceDeclInfo + _clang_index_getObjCInterfaceDeclInfo = _dylib.lookupFunction< + _c_clang_index_getObjCInterfaceDeclInfo, + _dart_clang_index_getObjCInterfaceDeclInfo>( + 'clang_index_getObjCInterfaceDeclInfo'); + +typedef _c_clang_index_getObjCInterfaceDeclInfo + = ffi.Pointer Function( + ffi.Pointer arg0, +); + +typedef _dart_clang_index_getObjCInterfaceDeclInfo + = ffi.Pointer Function( + ffi.Pointer arg0, +); + +ffi.Pointer clang_index_getObjCPropertyDeclInfo( + ffi.Pointer arg0, +) { + return _clang_index_getObjCPropertyDeclInfo( + arg0, + ); +} + +final _dart_clang_index_getObjCPropertyDeclInfo + _clang_index_getObjCPropertyDeclInfo = _dylib.lookupFunction< + _c_clang_index_getObjCPropertyDeclInfo, + _dart_clang_index_getObjCPropertyDeclInfo>( + 'clang_index_getObjCPropertyDeclInfo'); + +typedef _c_clang_index_getObjCPropertyDeclInfo + = ffi.Pointer Function( + ffi.Pointer arg0, +); + +typedef _dart_clang_index_getObjCPropertyDeclInfo + = ffi.Pointer Function( + ffi.Pointer arg0, +); + +ffi.Pointer + clang_index_getObjCProtocolRefListInfo( + ffi.Pointer arg0, +) { + return _clang_index_getObjCProtocolRefListInfo( + arg0, + ); +} + +final _dart_clang_index_getObjCProtocolRefListInfo + _clang_index_getObjCProtocolRefListInfo = _dylib.lookupFunction< + _c_clang_index_getObjCProtocolRefListInfo, + _dart_clang_index_getObjCProtocolRefListInfo>( + 'clang_index_getObjCProtocolRefListInfo'); + +typedef _c_clang_index_getObjCProtocolRefListInfo + = ffi.Pointer Function( + ffi.Pointer arg0, +); + +typedef _dart_clang_index_getObjCProtocolRefListInfo + = ffi.Pointer Function( + ffi.Pointer arg0, +); + +int clang_index_isEntityObjCContainerKind( + int arg0, +) { + return _clang_index_isEntityObjCContainerKind( + arg0, + ); +} + +final _dart_clang_index_isEntityObjCContainerKind + _clang_index_isEntityObjCContainerKind = _dylib.lookupFunction< + _c_clang_index_isEntityObjCContainerKind, + _dart_clang_index_isEntityObjCContainerKind>( + 'clang_index_isEntityObjCContainerKind'); + +typedef _c_clang_index_isEntityObjCContainerKind = ffi.Int32 Function( + ffi.Int32 arg0, +); + +typedef _dart_clang_index_isEntityObjCContainerKind = int Function( + int arg0, +); + +/// For setting a custom CXIdxClientContainer attached to a container. +void clang_index_setClientContainer( + ffi.Pointer arg0, + ffi.Pointer arg1, +) { + return _clang_index_setClientContainer( + arg0, + arg1, + ); +} + +final _dart_clang_index_setClientContainer _clang_index_setClientContainer = + _dylib.lookupFunction<_c_clang_index_setClientContainer, + _dart_clang_index_setClientContainer>('clang_index_setClientContainer'); + +typedef _c_clang_index_setClientContainer = ffi.Void Function( + ffi.Pointer arg0, + ffi.Pointer arg1, +); + +typedef _dart_clang_index_setClientContainer = void Function( + ffi.Pointer arg0, + ffi.Pointer arg1, +); + +/// For setting a custom CXIdxClientEntity attached to an entity. +void clang_index_setClientEntity( + ffi.Pointer arg0, + ffi.Pointer arg1, +) { + return _clang_index_setClientEntity( + arg0, + arg1, + ); +} + +final _dart_clang_index_setClientEntity _clang_index_setClientEntity = + _dylib.lookupFunction<_c_clang_index_setClientEntity, + _dart_clang_index_setClientEntity>('clang_index_setClientEntity'); + +typedef _c_clang_index_setClientEntity = ffi.Void Function( + ffi.Pointer arg0, + ffi.Pointer arg1, +); + +typedef _dart_clang_index_setClientEntity = void Function( + ffi.Pointer arg0, + ffi.Pointer arg1, +); + +/// Determine whether the given cursor kind represents an attribute. +int clang_isAttribute( + int arg0, +) { + return _clang_isAttribute( + arg0, + ); +} + +final _dart_clang_isAttribute _clang_isAttribute = + _dylib.lookupFunction<_c_clang_isAttribute, _dart_clang_isAttribute>( + 'clang_isAttribute'); + +typedef _c_clang_isAttribute = ffi.Uint32 Function( + ffi.Int32 arg0, +); + +typedef _dart_clang_isAttribute = int Function( + int arg0, +); + +/// Determine whether the given cursor kind represents a declaration. +int clang_isDeclaration( + int arg0, +) { + return _clang_isDeclaration( + arg0, + ); +} + +final _dart_clang_isDeclaration _clang_isDeclaration = + _dylib.lookupFunction<_c_clang_isDeclaration, _dart_clang_isDeclaration>( + 'clang_isDeclaration'); + +typedef _c_clang_isDeclaration = ffi.Uint32 Function( + ffi.Int32 arg0, +); + +typedef _dart_clang_isDeclaration = int Function( + int arg0, +); + +/// Determine whether the given cursor kind represents an expression. +int clang_isExpression( + int arg0, +) { + return _clang_isExpression( + arg0, + ); +} + +final _dart_clang_isExpression _clang_isExpression = + _dylib.lookupFunction<_c_clang_isExpression, _dart_clang_isExpression>( + 'clang_isExpression'); + +typedef _c_clang_isExpression = ffi.Uint32 Function( + ffi.Int32 arg0, +); + +typedef _dart_clang_isExpression = int Function( + int arg0, +); + +/// Determine whether the given header is guarded against multiple inclusions, either with the conventional #ifndef/#define/#endif macro guards or with #pragma once. +int clang_isFileMultipleIncludeGuarded( + ffi.Pointer tu, + ffi.Pointer file, +) { + return _clang_isFileMultipleIncludeGuarded( + tu, + file, + ); +} + +final _dart_clang_isFileMultipleIncludeGuarded + _clang_isFileMultipleIncludeGuarded = _dylib.lookupFunction< + _c_clang_isFileMultipleIncludeGuarded, + _dart_clang_isFileMultipleIncludeGuarded>( + 'clang_isFileMultipleIncludeGuarded'); + +typedef _c_clang_isFileMultipleIncludeGuarded = ffi.Uint32 Function( + ffi.Pointer tu, + ffi.Pointer file, +); + +typedef _dart_clang_isFileMultipleIncludeGuarded = int Function( + ffi.Pointer tu, + ffi.Pointer file, +); + +/// Determine whether the given cursor kind represents an invalid cursor. +int clang_isInvalid( + int arg0, +) { + return _clang_isInvalid( + arg0, + ); +} + +final _dart_clang_isInvalid _clang_isInvalid = + _dylib.lookupFunction<_c_clang_isInvalid, _dart_clang_isInvalid>( + 'clang_isInvalid'); + +typedef _c_clang_isInvalid = ffi.Uint32 Function( + ffi.Int32 arg0, +); + +typedef _dart_clang_isInvalid = int Function( + int arg0, +); + +/// * Determine whether the given cursor represents a preprocessing element, such as a preprocessor directive or macro instantiation. +int clang_isPreprocessing( + int arg0, +) { + return _clang_isPreprocessing( + arg0, + ); +} + +final _dart_clang_isPreprocessing _clang_isPreprocessing = _dylib + .lookupFunction<_c_clang_isPreprocessing, _dart_clang_isPreprocessing>( + 'clang_isPreprocessing'); + +typedef _c_clang_isPreprocessing = ffi.Uint32 Function( + ffi.Int32 arg0, +); + +typedef _dart_clang_isPreprocessing = int Function( + int arg0, +); + +/// Determine whether the given cursor kind represents a simple reference. +int clang_isReference( + int arg0, +) { + return _clang_isReference( + arg0, + ); +} + +final _dart_clang_isReference _clang_isReference = + _dylib.lookupFunction<_c_clang_isReference, _dart_clang_isReference>( + 'clang_isReference'); + +typedef _c_clang_isReference = ffi.Uint32 Function( + ffi.Int32 arg0, +); + +typedef _dart_clang_isReference = int Function( + int arg0, +); + +/// Determine whether the given cursor kind represents a statement. +int clang_isStatement( + int arg0, +) { + return _clang_isStatement( + arg0, + ); +} + +final _dart_clang_isStatement _clang_isStatement = + _dylib.lookupFunction<_c_clang_isStatement, _dart_clang_isStatement>( + 'clang_isStatement'); + +typedef _c_clang_isStatement = ffi.Uint32 Function( + ffi.Int32 arg0, +); + +typedef _dart_clang_isStatement = int Function( + int arg0, +); + +/// Determine whether the given cursor kind represents a translation unit. +int clang_isTranslationUnit( + int arg0, +) { + return _clang_isTranslationUnit( + arg0, + ); +} + +final _dart_clang_isTranslationUnit _clang_isTranslationUnit = _dylib + .lookupFunction<_c_clang_isTranslationUnit, _dart_clang_isTranslationUnit>( + 'clang_isTranslationUnit'); + +typedef _c_clang_isTranslationUnit = ffi.Uint32 Function( + ffi.Int32 arg0, +); + +typedef _dart_clang_isTranslationUnit = int Function( + int arg0, +); + +/// * Determine whether the given cursor represents a currently unexposed piece of the AST (e.g., CXCursor_UnexposedStmt). +int clang_isUnexposed( + int arg0, +) { + return _clang_isUnexposed( + arg0, + ); +} + +final _dart_clang_isUnexposed _clang_isUnexposed = + _dylib.lookupFunction<_c_clang_isUnexposed, _dart_clang_isUnexposed>( + 'clang_isUnexposed'); + +typedef _c_clang_isUnexposed = ffi.Uint32 Function( + ffi.Int32 arg0, +); + +typedef _dart_clang_isUnexposed = int Function( + int arg0, +); + +/// Deserialize a set of diagnostics from a Clang diagnostics bitcode file. +ffi.Pointer clang_loadDiagnostics( + ffi.Pointer file, + ffi.Pointer error, + ffi.Pointer errorString, +) { + return _clang_loadDiagnostics( + file, + error, + errorString, + ); +} + +final _dart_clang_loadDiagnostics _clang_loadDiagnostics = _dylib + .lookupFunction<_c_clang_loadDiagnostics, _dart_clang_loadDiagnostics>( + 'clang_loadDiagnostics'); + +typedef _c_clang_loadDiagnostics = ffi.Pointer Function( + ffi.Pointer file, + ffi.Pointer error, + ffi.Pointer errorString, +); + +typedef _dart_clang_loadDiagnostics = ffi.Pointer Function( + ffi.Pointer file, + ffi.Pointer error, + ffi.Pointer errorString, +); + +/// Same as clang_parseTranslationUnit2, but returns the CXTranslationUnit instead of an error code. In case of an error this routine returns a NULL CXTranslationUnit, without further detailed error codes. +ffi.Pointer clang_parseTranslationUnit( + ffi.Pointer CIdx, + ffi.Pointer source_filename, + ffi.Pointer> command_line_args, + int num_command_line_args, + ffi.Pointer unsaved_files, + int num_unsaved_files, + int options, +) { + return _clang_parseTranslationUnit( + CIdx, + source_filename, + command_line_args, + num_command_line_args, + unsaved_files, + num_unsaved_files, + options, + ); +} + +final _dart_clang_parseTranslationUnit _clang_parseTranslationUnit = + _dylib.lookupFunction<_c_clang_parseTranslationUnit, + _dart_clang_parseTranslationUnit>('clang_parseTranslationUnit'); + +typedef _c_clang_parseTranslationUnit = ffi.Pointer + Function( + ffi.Pointer CIdx, + ffi.Pointer source_filename, + ffi.Pointer> command_line_args, + ffi.Int32 num_command_line_args, + ffi.Pointer unsaved_files, + ffi.Uint32 num_unsaved_files, + ffi.Uint32 options, +); + +typedef _dart_clang_parseTranslationUnit = ffi.Pointer + Function( + ffi.Pointer CIdx, + ffi.Pointer source_filename, + ffi.Pointer> command_line_args, + int num_command_line_args, + ffi.Pointer unsaved_files, + int num_unsaved_files, + int options, +); + +/// Parse the given source file and the translation unit corresponding to that file. +int clang_parseTranslationUnit2( + ffi.Pointer CIdx, + ffi.Pointer source_filename, + ffi.Pointer> command_line_args, + int num_command_line_args, + ffi.Pointer unsaved_files, + int num_unsaved_files, + int options, + ffi.Pointer> out_TU, +) { + return _clang_parseTranslationUnit2( + CIdx, + source_filename, + command_line_args, + num_command_line_args, + unsaved_files, + num_unsaved_files, + options, + out_TU, + ); +} + +final _dart_clang_parseTranslationUnit2 _clang_parseTranslationUnit2 = + _dylib.lookupFunction<_c_clang_parseTranslationUnit2, + _dart_clang_parseTranslationUnit2>('clang_parseTranslationUnit2'); + +typedef _c_clang_parseTranslationUnit2 = ffi.Int32 Function( + ffi.Pointer CIdx, + ffi.Pointer source_filename, + ffi.Pointer> command_line_args, + ffi.Int32 num_command_line_args, + ffi.Pointer unsaved_files, + ffi.Uint32 num_unsaved_files, + ffi.Uint32 options, + ffi.Pointer> out_TU, +); + +typedef _dart_clang_parseTranslationUnit2 = int Function( + ffi.Pointer CIdx, + ffi.Pointer source_filename, + ffi.Pointer> command_line_args, + int num_command_line_args, + ffi.Pointer unsaved_files, + int num_unsaved_files, + int options, + ffi.Pointer> out_TU, +); + +/// Same as clang_parseTranslationUnit2 but requires a full command line for command_line_args including argv[0]. This is useful if the standard library paths are relative to the binary. +int clang_parseTranslationUnit2FullArgv( + ffi.Pointer CIdx, + ffi.Pointer source_filename, + ffi.Pointer> command_line_args, + int num_command_line_args, + ffi.Pointer unsaved_files, + int num_unsaved_files, + int options, + ffi.Pointer> out_TU, +) { + return _clang_parseTranslationUnit2FullArgv( + CIdx, + source_filename, + command_line_args, + num_command_line_args, + unsaved_files, + num_unsaved_files, + options, + out_TU, + ); +} + +final _dart_clang_parseTranslationUnit2FullArgv + _clang_parseTranslationUnit2FullArgv = _dylib.lookupFunction< + _c_clang_parseTranslationUnit2FullArgv, + _dart_clang_parseTranslationUnit2FullArgv>( + 'clang_parseTranslationUnit2FullArgv'); + +typedef _c_clang_parseTranslationUnit2FullArgv = ffi.Int32 Function( + ffi.Pointer CIdx, + ffi.Pointer source_filename, + ffi.Pointer> command_line_args, + ffi.Int32 num_command_line_args, + ffi.Pointer unsaved_files, + ffi.Uint32 num_unsaved_files, + ffi.Uint32 options, + ffi.Pointer> out_TU, +); + +typedef _dart_clang_parseTranslationUnit2FullArgv = int Function( + ffi.Pointer CIdx, + ffi.Pointer source_filename, + ffi.Pointer> command_line_args, + int num_command_line_args, + ffi.Pointer unsaved_files, + int num_unsaved_files, + int options, + ffi.Pointer> out_TU, +); + +/// Dispose the remapping. +void clang_remap_dispose( + ffi.Pointer arg0, +) { + return _clang_remap_dispose( + arg0, + ); +} + +final _dart_clang_remap_dispose _clang_remap_dispose = + _dylib.lookupFunction<_c_clang_remap_dispose, _dart_clang_remap_dispose>( + 'clang_remap_dispose'); + +typedef _c_clang_remap_dispose = ffi.Void Function( + ffi.Pointer arg0, +); + +typedef _dart_clang_remap_dispose = void Function( + ffi.Pointer arg0, +); + +/// Get the original and the associated filename from the remapping. +void clang_remap_getFilenames( + ffi.Pointer arg0, + int index, + ffi.Pointer original, + ffi.Pointer transformed, +) { + return _clang_remap_getFilenames( + arg0, + index, + original, + transformed, + ); +} + +final _dart_clang_remap_getFilenames _clang_remap_getFilenames = + _dylib.lookupFunction<_c_clang_remap_getFilenames, + _dart_clang_remap_getFilenames>('clang_remap_getFilenames'); + +typedef _c_clang_remap_getFilenames = ffi.Void Function( + ffi.Pointer arg0, + ffi.Uint32 index, + ffi.Pointer original, + ffi.Pointer transformed, +); + +typedef _dart_clang_remap_getFilenames = void Function( + ffi.Pointer arg0, + int index, + ffi.Pointer original, + ffi.Pointer transformed, +); + +/// Determine the number of remappings. +int clang_remap_getNumFiles( + ffi.Pointer arg0, +) { + return _clang_remap_getNumFiles( + arg0, + ); +} + +final _dart_clang_remap_getNumFiles _clang_remap_getNumFiles = _dylib + .lookupFunction<_c_clang_remap_getNumFiles, _dart_clang_remap_getNumFiles>( + 'clang_remap_getNumFiles'); + +typedef _c_clang_remap_getNumFiles = ffi.Uint32 Function( + ffi.Pointer arg0, +); + +typedef _dart_clang_remap_getNumFiles = int Function( + ffi.Pointer arg0, +); + +/// Reparse the source files that produced this translation unit. +int clang_reparseTranslationUnit( + ffi.Pointer TU, + int num_unsaved_files, + ffi.Pointer unsaved_files, + int options, +) { + return _clang_reparseTranslationUnit( + TU, + num_unsaved_files, + unsaved_files, + options, + ); +} + +final _dart_clang_reparseTranslationUnit _clang_reparseTranslationUnit = + _dylib.lookupFunction<_c_clang_reparseTranslationUnit, + _dart_clang_reparseTranslationUnit>('clang_reparseTranslationUnit'); + +typedef _c_clang_reparseTranslationUnit = ffi.Int32 Function( + ffi.Pointer TU, + ffi.Uint32 num_unsaved_files, + ffi.Pointer unsaved_files, + ffi.Uint32 options, +); + +typedef _dart_clang_reparseTranslationUnit = int Function( + ffi.Pointer TU, + int num_unsaved_files, + ffi.Pointer unsaved_files, + int options, +); + +/// Saves a translation unit into a serialized representation of that translation unit on disk. +int clang_saveTranslationUnit( + ffi.Pointer TU, + ffi.Pointer FileName, + int options, +) { + return _clang_saveTranslationUnit( + TU, + FileName, + options, + ); +} + +final _dart_clang_saveTranslationUnit _clang_saveTranslationUnit = + _dylib.lookupFunction<_c_clang_saveTranslationUnit, + _dart_clang_saveTranslationUnit>('clang_saveTranslationUnit'); + +typedef _c_clang_saveTranslationUnit = ffi.Int32 Function( + ffi.Pointer TU, + ffi.Pointer FileName, + ffi.Uint32 options, +); + +typedef _dart_clang_saveTranslationUnit = int Function( + ffi.Pointer TU, + ffi.Pointer FileName, + int options, +); + +/// Sort the code-completion results in case-insensitive alphabetical order. +void clang_sortCodeCompletionResults( + ffi.Pointer Results, + int NumResults, +) { + return _clang_sortCodeCompletionResults( + Results, + NumResults, + ); +} + +final _dart_clang_sortCodeCompletionResults _clang_sortCodeCompletionResults = + _dylib.lookupFunction<_c_clang_sortCodeCompletionResults, + _dart_clang_sortCodeCompletionResults>( + 'clang_sortCodeCompletionResults'); + +typedef _c_clang_sortCodeCompletionResults = ffi.Void Function( + ffi.Pointer Results, + ffi.Uint32 NumResults, +); + +typedef _dart_clang_sortCodeCompletionResults = void Function( + ffi.Pointer Results, + int NumResults, +); + +/// Suspend a translation unit in order to free memory associated with it. +int clang_suspendTranslationUnit( + ffi.Pointer arg0, +) { + return _clang_suspendTranslationUnit( + arg0, + ); +} + +final _dart_clang_suspendTranslationUnit _clang_suspendTranslationUnit = + _dylib.lookupFunction<_c_clang_suspendTranslationUnit, + _dart_clang_suspendTranslationUnit>('clang_suspendTranslationUnit'); + +typedef _c_clang_suspendTranslationUnit = ffi.Uint32 Function( + ffi.Pointer arg0, +); + +typedef _dart_clang_suspendTranslationUnit = int Function( + ffi.Pointer arg0, +); + +/// Enable/disable crash recovery. +void clang_toggleCrashRecovery( + int isEnabled, +) { + return _clang_toggleCrashRecovery( + isEnabled, + ); +} + +final _dart_clang_toggleCrashRecovery _clang_toggleCrashRecovery = + _dylib.lookupFunction<_c_clang_toggleCrashRecovery, + _dart_clang_toggleCrashRecovery>('clang_toggleCrashRecovery'); + +typedef _c_clang_toggleCrashRecovery = ffi.Void Function( + ffi.Uint32 isEnabled, +); + +typedef _dart_clang_toggleCrashRecovery = void Function( + int isEnabled, +); + +/// Visitor is a function pointer with parameters having pointers to cxcursor instead of cxcursor by default. +int clang_visitChildren_wrap( + ffi.Pointer parent, + ffi.Pointer> _modifiedVisitor, + ffi.Pointer clientData, +) { + return _clang_visitChildren_wrap( + parent, + _modifiedVisitor, + clientData, + ); +} + +final _dart_clang_visitChildren_wrap _clang_visitChildren_wrap = + _dylib.lookupFunction<_c_clang_visitChildren_wrap, + _dart_clang_visitChildren_wrap>('clang_visitChildren_wrap'); + +typedef _c_clang_visitChildren_wrap = ffi.Uint32 Function( + ffi.Pointer parent, + ffi.Pointer> _modifiedVisitor, + ffi.Pointer clientData, +); + +typedef _dart_clang_visitChildren_wrap = int Function( + ffi.Pointer parent, + ffi.Pointer> _modifiedVisitor, + ffi.Pointer clientData, +); diff --git a/example/libclang-example/pubspec.yaml b/example/libclang-example/pubspec.yaml new file mode 100644 index 00000000..bd000c69 --- /dev/null +++ b/example/libclang-example/pubspec.yaml @@ -0,0 +1,63 @@ +# Copyright (c) 2020, the Dart project authors. Please see the AUTHORS file +# for details. All rights reserved. Use of this source code is governed by a +# BSD-style license that can be found in the LICENSE file. + +name: libclang_example + +environment: + sdk: '>=2.8.1 <3.0.0' + +dev_dependencies: + ffigen: + path: '../../' + +ffigen: + output: 'generated_bindings.dart' + sort: true + + # Bash style Glob matching is also supported. + # TODO(11): Globs dont work on windows if they begin with '.' or '..'. + headers: + - '../../tool/wrapped_libclang/wrapper.c' + + # Excludes included headers based on their names (not fullpath name). + header-filter: + include: + - 'wrapper.c' + - 'CXString.h' + - 'Index.h' + + compiler-opts: '-I/usr/lib/llvm-9/include/ -I/usr/lib/llvm-10/include/ -IC:\Progra~1\LLVM\include -I/usr/local/opt/llvm/include/ -I/Applications/Xcode.app/Contents/Developer/Platforms/MacOSX.platform/Developer/SDKs/MacOSX.sdk/usr/include/' + functions: + include: + matches: + # Should be valid regexp. + - 'clang_.*' + structs: + include: + matches: + - 'CX.*' + enums: + include: + # Compares the exact name. + names: + - 'CXTypeKind' + - 'CXGlobalOptFlags' + + # These are optional and also default, + # Omitting any and the default will be used. + size-map: + char: 1 + unsigned char: 1 + short: 2 + unsigned short: 2 + int: 4 + unsigned int: 4 + long: 8 + unsigned long: 8 + long long: 8 + unsigned long long: 8 + enum: 4 + + # True by default + extract-comments: true diff --git a/example/libclang-example/readme.md b/example/libclang-example/readme.md new file mode 100644 index 00000000..4918a378 --- /dev/null +++ b/example/libclang-example/readme.md @@ -0,0 +1,11 @@ +# Libclang example + +Demonstrates generating bindings for [Libclang](https://clang.llvm.org/doxygen/group__CINDEX.html). +This example actually uses a C file used in this package itself, ([wrapper.c](../../tool/wrapped_libclang/wrapper.c)), which adds a few more wrapper functions atop Libclang. + +## Generating bindings +At the root of this example (`example/libclang-example`), run - +``` +pub run ffigen:generate +``` +This will generate bindings in a file: [generated_bindings.dart](./generated_bindings.dart). diff --git a/example/simple/.gitignore b/example/simple/.gitignore new file mode 100644 index 00000000..1b051642 --- /dev/null +++ b/example/simple/.gitignore @@ -0,0 +1,11 @@ +# Files and directories created by pub. +.dart_tool/ +.packages +# Remove the following pattern if you wish to check in your lock file. +pubspec.lock + +# Conventional directory for build outputs. +build/ + +# Directory created by dartdoc. +doc/api/ diff --git a/example/simple/README.md b/example/simple/README.md new file mode 100644 index 00000000..6fc5243e --- /dev/null +++ b/example/simple/README.md @@ -0,0 +1,10 @@ +# Simple header example + +A very simple example, generates bindings for a very small header file (`headers/example.h`). + +## Generating bindings +At the root of this example (`example/simple`), run - +``` +pub run ffigen:generate +``` +This will generate bindings in a file: [generated_bindings.dart](./generated_bindings.dart). diff --git a/example/simple/generated_bindings.dart b/example/simple/generated_bindings.dart new file mode 100644 index 00000000..6e3a97b8 --- /dev/null +++ b/example/simple/generated_bindings.dart @@ -0,0 +1,132 @@ +/// AUTO GENERATED FILE, DO NOT EDIT. +/// +/// Generated by `package:ffigen`. +import 'dart:ffi' as ffi; + +/// Holds the Dynamic library. +ffi.DynamicLibrary _dylib; + +/// Initialises the Dynamic library. +void init(ffi.DynamicLibrary dylib) { + _dylib = dylib; +} + +/// Adds 2 integers. +int sum( + int a, + int b, +) { + return _sum( + a, + b, + ); +} + +final _dart_sum _sum = _dylib.lookupFunction<_c_sum, _dart_sum>('sum'); + +typedef _c_sum = ffi.Int32 Function( + ffi.Int32 a, + ffi.Int32 b, +); + +typedef _dart_sum = int Function( + int a, + int b, +); + +/// Subtracts 2 integers. +int subtract( + ffi.Pointer a, + int b, +) { + return _subtract( + a, + b, + ); +} + +final _dart_subtract _subtract = + _dylib.lookupFunction<_c_subtract, _dart_subtract>('subtract'); + +typedef _c_subtract = ffi.Int32 Function( + ffi.Pointer a, + ffi.Int32 b, +); + +typedef _dart_subtract = int Function( + ffi.Pointer a, + int b, +); + +/// Multiplies 2 integers, returns pointer to an integer,. +ffi.Pointer multiply( + int a, + int b, +) { + return _multiply( + a, + b, + ); +} + +final _dart_multiply _multiply = + _dylib.lookupFunction<_c_multiply, _dart_multiply>('multiply'); + +typedef _c_multiply = ffi.Pointer Function( + ffi.Int32 a, + ffi.Int32 b, +); + +typedef _dart_multiply = ffi.Pointer Function( + int a, + int b, +); + +/// Divides 2 integers, returns pointer to a float. +ffi.Pointer divide( + int a, + int b, +) { + return _divide( + a, + b, + ); +} + +final _dart_divide _divide = + _dylib.lookupFunction<_c_divide, _dart_divide>('divide'); + +typedef _c_divide = ffi.Pointer Function( + ffi.Int32 a, + ffi.Int32 b, +); + +typedef _dart_divide = ffi.Pointer Function( + int a, + int b, +); + +/// Divides 2 floats, returns a pointer to double. +ffi.Pointer dividePercision( + ffi.Pointer a, + ffi.Pointer b, +) { + return _dividePercision( + a, + b, + ); +} + +final _dart_dividePercision _dividePercision = + _dylib.lookupFunction<_c_dividePercision, _dart_dividePercision>( + 'dividePercision'); + +typedef _c_dividePercision = ffi.Pointer Function( + ffi.Pointer a, + ffi.Pointer b, +); + +typedef _dart_dividePercision = ffi.Pointer Function( + ffi.Pointer a, + ffi.Pointer b, +); diff --git a/example/simple/headers/example.h b/example/simple/headers/example.h new file mode 100644 index 00000000..0f936ee3 --- /dev/null +++ b/example/simple/headers/example.h @@ -0,0 +1,18 @@ +// Copyright (c) 2020, the Dart project authors. Please see the AUTHORS file +// for details. All rights reserved. Use of this source code is governed by a +// BSD-style license that can be found in the LICENSE file. + +/** Adds 2 integers. */ +int sum(int a, int b); + +/** Subtracts 2 integers. */ +int subtract(int *a, int b); + +/** Multiplies 2 integers, returns pointer to an integer,. */ +int *multiply(int a, int b); + +/** Divides 2 integers, returns pointer to a float. */ +float *divide(int a, int b); + +/** Divides 2 floats, returns a pointer to double. */ +double *dividePercision(float *a, float *b); diff --git a/example/simple/pubspec.yaml b/example/simple/pubspec.yaml new file mode 100644 index 00000000..454c138f --- /dev/null +++ b/example/simple/pubspec.yaml @@ -0,0 +1,17 @@ +# Copyright (c) 2020, the Dart project authors. Please see the AUTHORS file +# for details. All rights reserved. Use of this source code is governed by a +# BSD-style license that can be found in the LICENSE file. + +name: simple_example + +environment: + sdk: '>=2.8.1 <3.0.0' + +dev_dependencies: + ffigen: + path: '../../' + +ffigen: + output: 'generated_bindings.dart' + headers: + - 'headers/example.h' diff --git a/lib/src/README.md b/lib/src/README.md new file mode 100644 index 00000000..2832400e --- /dev/null +++ b/lib/src/README.md @@ -0,0 +1,41 @@ +## Project Structure + +- `bin` - Contains generate.dart script which end user will execute. +- `tool` - Contains script to generate LibClang bindings using Code_Generator submodule (dev use only). +- `example` - Example projects which demonstrate generation of bindings for given C header files. +- `lib/src/code_generator` - Generates binding files. +- `lib/src/config_provider` - Holds configurations to be passed to other modules. +- `lib/src/header_parser` - Parses header files, utilises clang_bindings. + +## Basic Workflow +1. The User provides the location all the header files (as a list of globs or filepaths), +For each header file, we create a translation unit and parse the `declarations` in it +to the bindings. +2. User can provide `header filters` to select which declaration from a particular header file should be added to the generated bindings. The can provide a list of header 'names' to include/exclude. +We compare the header file name (not the exact path) to decide. +The default behaviour is to include everything that's included when parsing a header. +3. Use can provide Compiler options, which are passed to clang compiler as it is. +4. All bindings are generated in a single file. + +# Code Details +## Modules +We are using libclang to parse header files. +This project is roughly divided in 3 major modules - +### code_generator +Converts a library(all bindings) to an actual string representation. +- Library (output of the header parser). +- Writer (provides configurations for generating bindings). +- Binding (base class for all bindings - Func, Struc, Global, EnumClass, etc). +### config_provider +This takes care of validating user config files, printing config warnings and errors, +converting config.yaml to a format the header_parser can use. +- Spec (represents a single config, which a user can provide in the config file). +- Config (holds all the config which will be required by header parser). +### header_parser +Uses libclang to convert the header to a Library which is then used by code_generator. +- clang_bindings (bindings to libclang which are used for parsing). +- sub_parsers (each sub-parser parses a particular kind of declaration - struct, function, typedef, enum). +- type_extractor (extracts types from variables, function parameters, return types). +- includer (tells what should/shouldn't be included depending of config). +- parser (Main Entrypoint) (creates translation units for all header files, and sets up parsing them). +- translation_unit_parser (parses header files, splits declarations and feeds them to their respective sub_parsers). \ No newline at end of file diff --git a/lib/src/code_generator.dart b/lib/src/code_generator.dart new file mode 100644 index 00000000..9eb01b64 --- /dev/null +++ b/lib/src/code_generator.dart @@ -0,0 +1,17 @@ +// Copyright (c) 2020, the Dart project authors. Please see the AUTHORS file +// for details. All rights reserved. Use of this source code is governed by a +// BSD-style license that can be found in the LICENSE file. + +/// Generates FFI bindings for a given [Library]. +library code_generator; + +export 'code_generator/binding.dart'; +export 'code_generator/constant.dart'; +export 'code_generator/enum_class.dart'; +export 'code_generator/func.dart'; +export 'code_generator/global.dart'; +export 'code_generator/library.dart'; +export 'code_generator/struc.dart'; +export 'code_generator/type.dart'; +export 'code_generator/typedef.dart'; + diff --git a/lib/src/code_generator/binding.dart b/lib/src/code_generator/binding.dart new file mode 100644 index 00000000..127c0d25 --- /dev/null +++ b/lib/src/code_generator/binding.dart @@ -0,0 +1,20 @@ +// Copyright (c) 2020, the Dart project authors. Please see the AUTHORS file +// for details. All rights reserved. Use of this source code is governed by a +// BSD-style license that can be found in the LICENSE file. + +import 'package:meta/meta.dart'; + +import 'binding_string.dart'; +import 'writer.dart'; + +/// Base class for all Bindings. +abstract class Binding { + final String name; + + final String dartDoc; + + const Binding({@required this.name, this.dartDoc}); + + /// Converts a Binding to its actual string representation. + BindingString toBindingString(Writer w); +} diff --git a/lib/src/code_generator/binding_string.dart b/lib/src/code_generator/binding_string.dart new file mode 100644 index 00000000..c0d4325f --- /dev/null +++ b/lib/src/code_generator/binding_string.dart @@ -0,0 +1,27 @@ +// Copyright (c) 2020, the Dart project authors. Please see the AUTHORS file +// for details. All rights reserved. Use of this source code is governed by a +// BSD-style license that can be found in the LICENSE file. + +import 'package:meta/meta.dart'; + +/// A Binding's String representation. +class BindingString { + // Meta data, (not used for generation). + final BindingStringType type; + final String string; + + const BindingString({@required this.type, @required this.string}); + + @override + String toString() => string; +} + +/// A [BindingString]'s type. +enum BindingStringType { + func, + struc, + constant, + global, + enumClass, + typeDef, +} diff --git a/lib/src/code_generator/constant.dart b/lib/src/code_generator/constant.dart new file mode 100644 index 00000000..bef22d8d --- /dev/null +++ b/lib/src/code_generator/constant.dart @@ -0,0 +1,53 @@ +// Copyright (c) 2020, the Dart project authors. Please see the AUTHORS file +// for details. All rights reserved. Use of this source code is governed by a +// BSD-style license that can be found in the LICENSE file. + +import 'package:meta/meta.dart'; + +import 'binding.dart'; +import 'binding_string.dart'; +import 'type.dart'; +import 'writer.dart'; + +/// A simple Constant. +/// +/// Expands to - +/// ```dart +/// const = ; +/// ``` +/// +/// Example - +/// ```dart +/// const int name = 10; +/// ``` +class Constant extends Binding { + final Type type; + + /// The rawValue is pasted as it is. + /// + /// Put quotes if type is a string. + final String rawValue; + + const Constant({ + @required String name, + String dartDoc, + @required this.type, + @required this.rawValue, + }) : super(name: name, dartDoc: dartDoc); + + @override + BindingString toBindingString(Writer w) { + final s = StringBuffer(); + + if (dartDoc != null) { + s.write('/// '); + s.writeAll(dartDoc.split('\n'), '\n/// '); + s.write('\n'); + } + + s.write('const ${type.getDartType(w)} $name = $rawValue;\n\n'); + + return BindingString( + type: BindingStringType.constant, string: s.toString()); + } +} diff --git a/lib/src/code_generator/enum_class.dart b/lib/src/code_generator/enum_class.dart new file mode 100644 index 00000000..90faf5be --- /dev/null +++ b/lib/src/code_generator/enum_class.dart @@ -0,0 +1,69 @@ +// Copyright (c) 2020, the Dart project authors. Please see the AUTHORS file +// for details. All rights reserved. Use of this source code is governed by a +// BSD-style license that can be found in the LICENSE file. + +import 'package:meta/meta.dart'; + +import 'binding.dart'; +import 'binding_string.dart'; +import 'writer.dart'; + +/// A binding for enums in C. +/// +/// For a C enum - +/// ```c +/// enum Fruits {apple, banana = 10}; +/// ``` +/// The generated dart code is +/// +/// ```dart +/// class Fruits { +/// static const apple = 0; +/// static const banana = 10; +/// } +/// ``` +class EnumClass extends Binding { + final List enumConstants; + + EnumClass({ + @required String name, + String dartDoc, + List enumConstants, + }) : enumConstants = enumConstants ?? [], + super(name: name, dartDoc: dartDoc); + + @override + BindingString toBindingString(Writer w) { + final s = StringBuffer(); + + if (dartDoc != null) { + s.write('/// '); + s.writeAll(dartDoc.split('\n'), '\n/// '); + s.write('\n'); + } + + // Print enclosing class. + s.write('class $name {\n'); + const depth = ' '; + for (final ec in enumConstants) { + if (ec.dartDoc != null) { + s.write(depth + '/// '); + s.writeAll(ec.dartDoc.split('\n'), '\n' + depth + '/// '); + s.write('\n'); + } + s.write(depth + 'static const int ${ec.name} = ${ec.value};\n'); + } + s.write('}\n\n'); + + return BindingString( + type: BindingStringType.enumClass, string: s.toString()); + } +} + +/// Represents a single value in an enum. +class EnumConstant { + final String dartDoc; + final String name; + final int value; + const EnumConstant({@required this.name, @required this.value, this.dartDoc}); +} diff --git a/lib/src/code_generator/func.dart b/lib/src/code_generator/func.dart new file mode 100644 index 00000000..688c573c --- /dev/null +++ b/lib/src/code_generator/func.dart @@ -0,0 +1,104 @@ +// Copyright (c) 2020, the Dart project authors. Please see the AUTHORS file +// for details. All rights reserved. Use of this source code is governed by a +// BSD-style license that can be found in the LICENSE file. + +import 'package:meta/meta.dart'; + +import 'binding.dart'; +import 'binding_string.dart'; +import 'type.dart'; +import 'writer.dart'; + +/// A binding for C function. +/// +/// For a C function - +/// ```c +/// int sum(int a, int b); +/// ``` +/// The Generated dart code is - +/// ```dart +/// int sum(int a, int b) { +/// return _sum(a, b); +/// } +/// +/// final _dart_sum _sum = _dylib.lookupFunction<_c_sum, _dart_sum>('sum'); +/// +/// typedef _c_sum = ffi.Int32 Function(ffi.Int32 a, ffi.Int32 b); +/// +/// typedef _dart_sum = int Function(int a, int b); +/// ``` +class Func extends Binding { + final Type returnType; + final List parameters; + + Func({ + @required String name, + String dartDoc, + @required this.returnType, + List parameters, + }) : parameters = parameters ?? [], + super(name: name, dartDoc: dartDoc) { + for (var i = 0; i < this.parameters.length; i++) { + if (this.parameters[i].name == null || + this.parameters[i].name.trim() == '') { + this.parameters[i].name = 'arg$i'; + } + } + } + + @override + BindingString toBindingString(Writer w) { + final s = StringBuffer(); + + final funcVarName = '_$name'; + final typedefC = '_c_$name'; + final typedefDart = '_dart_$name'; + + if (dartDoc != null) { + s.write('/// '); + s.writeAll(dartDoc.split('\n'), '\n/// '); + s.write('\n'); + } + + // Write enclosing function. + s.write('${returnType.getDartType(w)} $name(\n'); + for (final p in parameters) { + s.write(' ${p.type.getDartType(w)} ${p.name},\n'); + } + s.write(') {\n'); + s.write(' return $funcVarName(\n'); + for (final p in parameters) { + s.write(' ${p.name},\n'); + } + s.write(' );\n'); + s.write('}\n\n'); + + // Write function with dylib lookup. + s.write( + "final $typedefDart $funcVarName = ${w.dylibIdentifier}.lookupFunction<$typedefC,$typedefDart>('$name');\n\n"); + + // Write typdef for C. + s.write('typedef $typedefC = ${returnType.getCType(w)} Function(\n'); + for (final p in parameters) { + s.write(' ${p.type.getCType(w)} ${p.name},\n'); + } + s.write(');\n\n'); + + // Write typdef for dart. + s.write('typedef $typedefDart = ${returnType.getDartType(w)} Function(\n'); + for (final p in parameters) { + s.write(' ${p.type.getDartType(w)} ${p.name},\n'); + } + s.write(');\n\n'); + + return BindingString(type: BindingStringType.func, string: s.toString()); + } +} + +/// Represents a Function's parameter. +class Parameter { + String name; + final Type type; + + Parameter({this.name, @required this.type}); +} diff --git a/lib/src/code_generator/global.dart b/lib/src/code_generator/global.dart new file mode 100644 index 00000000..8729785f --- /dev/null +++ b/lib/src/code_generator/global.dart @@ -0,0 +1,46 @@ +// Copyright (c) 2020, the Dart project authors. Please see the AUTHORS file +// for details. All rights reserved. Use of this source code is governed by a +// BSD-style license that can be found in the LICENSE file. + +import 'package:meta/meta.dart'; + +import 'binding.dart'; +import 'binding_string.dart'; +import 'type.dart'; +import 'writer.dart'; + +/// A binding to a global variable +/// +/// For a C global variable - +/// ```c +/// int a; +/// ``` +/// The generated dart code is - +/// ```dart +/// final int a = _dylib.lookup('a').value; +/// ``` +class Global extends Binding { + final Type type; + + const Global({ + @required String name, + @required this.type, + String dartDoc, + }) : super(name: name, dartDoc: dartDoc); + + @override + BindingString toBindingString(Writer w) { + final s = StringBuffer(); + + if (dartDoc != null) { + s.write('/// '); + s.writeAll(dartDoc.split('\n'), '\n/// '); + s.write('\n'); + } + + s.write( + "final ${type.getDartType(w)} $name = ${w.dylibIdentifier}.lookup<${type.getCType(w)}>('$name').value;\n\n"); + + return BindingString(type: BindingStringType.global, string: s.toString()); + } +} diff --git a/lib/src/code_generator/library.dart b/lib/src/code_generator/library.dart new file mode 100644 index 00000000..8ae4a06e --- /dev/null +++ b/lib/src/code_generator/library.dart @@ -0,0 +1,83 @@ +// Copyright (c) 2020, the Dart project authors. Please see the AUTHORS file +// for details. All rights reserved. Use of this source code is governed by a +// BSD-style license that can be found in the LICENSE file. + +import 'dart:io'; + +import 'package:logging/logging.dart'; +import 'package:meta/meta.dart'; + +import 'binding.dart'; +import 'writer.dart'; + +var _logger = Logger('code_generator'); + +/// Container for all Bindings. +class Library { + /// Variable identifier used for dynamicLibrary. Defaults to `_dylib`, + final String dylibIdentifier; + + /// Init function for providing dynamic library. Defaults to `init`, + /// + /// Can be renamed in case of name conflicts with something else. + final String initFunctionIdentifier; + + /// Header of file. + final String header; + + /// List of bindings in this library. + final List bindings; + + Library({ + @required this.bindings, + this.dylibIdentifier = '_dylib', + this.initFunctionIdentifier = 'init', + this.header, + }) : assert(dylibIdentifier != null), + assert(initFunctionIdentifier != null); + + /// Sort all bindings in alphabetical order. + void sort() { + bindings.sort((b1, b2) => b1.name.compareTo(b2.name)); + } + + /// Generates [file] by generating C bindings. + /// + /// If format is true(default), 'dartfmt -w $PATH' will be called to format the generated file. + void generateFile(File file, {bool format = true}) { + file.writeAsStringSync(generate()); + if (format) { + _dartFmt(file.path); + } + } + + /// Generates bindings and stores it in given [Writer]. + void _generate(Writer w) { + w.header = header; + for (final b in bindings) { + w.addBindingString(b.toBindingString(w)); + } + } + + /// Formats a file using `dartfmt`. + void _dartFmt(String path) { + final result = Process.runSync('dartfmt', ['-w', path], + runInShell: Platform.isWindows); + if (result.stderr.toString().isNotEmpty) { + _logger.severe(result.stderr); + } + } + + /// Generates the bindings. + String generate() { + final w = Writer( + dylibIdentifier: dylibIdentifier, + initFunctionIdentifier: initFunctionIdentifier, + ); + _generate(w); + return w.generate(); + } + + @override + bool operator ==(Object o) => o is Library && o.generate() == generate(); +} diff --git a/lib/src/code_generator/struc.dart b/lib/src/code_generator/struc.dart new file mode 100644 index 00000000..391dc2ed --- /dev/null +++ b/lib/src/code_generator/struc.dart @@ -0,0 +1,194 @@ +// Copyright (c) 2020, the Dart project authors. Please see the AUTHORS file +// for details. All rights reserved. Use of this source code is governed by a +// BSD-style license that can be found in the LICENSE file. + +import 'package:meta/meta.dart'; + +import 'binding.dart'; +import 'binding_string.dart'; +import 'type.dart'; +import 'writer.dart'; + +/// A binding for C Struct. +/// +/// For a C structure - +/// ```c +/// struct C { +/// int a; +/// double b; +/// int c; +/// }; +/// ``` +/// The generated dart code is - +/// ```dart +/// class Struct extends ffi.Struct{ +/// @ffi.Int32() +/// int a; +/// +/// @ffi.Double() +/// double b; +/// +/// @ffi.Uint8() +/// int c; +/// +/// } +/// ``` +class Struc extends Binding { + final List members; + + Struc({ + @required String name, + String dartDoc, + List members, + }) : members = members ?? [], + super(name: name, dartDoc: dartDoc); + + @override + BindingString toBindingString(Writer w) { + final s = StringBuffer(); + + if (dartDoc != null) { + s.write('/// '); + s.writeAll(dartDoc.split('\n'), '\n/// '); + s.write('\n'); + } + + final helpers = []; + + // Write class declaration. + s.write('class $name extends ${w.ffiLibraryPrefix}.Struct{\n'); + for (final m in members) { + if (m.type.broadType == BroadType.ConstantArray) { + // TODO(5): Remove array helpers when inline array support arives. + final arrayHelper = ArrayHelper( + helperClassName: '_ArrayHelper_${name}_${m.name}', + elementType: m.type.elementType, + length: 3, + name: m.name, + structName: name, + elementNamePrefix: '_${m.name}_item_', + ); + s.write(arrayHelper.declarationString(w)); + helpers.add(arrayHelper); + } else { + if (m.type.isPrimitive) { + s.write(' @${m.type.getCType(w)}()\n'); + } + s.write(' ${m.type.getDartType(w)} ${m.name};\n\n'); + } + } + s.write('}\n\n'); + + for (final helper in helpers) { + s.write(helper.helperClassString(w)); + } + + return BindingString(type: BindingStringType.struc, string: s.toString()); + } +} + +class Member { + final String name; + final Type type; + + const Member({this.name, this.type}); +} + +// Helper bindings for struct array. +class ArrayHelper { + final Type elementType; + final int length; + final String structName; + + final String name; + final String helperClassName; + final String elementNamePrefix; + + ArrayHelper({ + @required this.elementType, + @required this.length, + @required this.structName, + @required this.name, + @required this.helperClassName, + @required this.elementNamePrefix, + }); + + /// Create declaration binding, added inside the struct binding. + String declarationString(Writer w) { + final s = StringBuffer(); + final arrayDartType = elementType.getDartType(w); + final arrayCType = elementType.getCType(w); + + for (var i = 0; i < length; i++) { + if (elementType.isPrimitive) { + s.write(' @${arrayCType}()\n'); + } + s.write(' ${arrayDartType} ${elementNamePrefix}$i;\n'); + } + + s.write('/// helper for array, supports `[]` operator\n'); + s.write( + '$helperClassName get $name => ${helperClassName}(this, $length);\n'); + + return s.toString(); + } + + /// Creates an array helper binding for struct array. + String helperClassString(Writer w) { + final s = StringBuffer(); + + final arrayType = elementType.getDartType(w); + + s.write('/// Helper for array $name in struct $structName\n'); + + // Write class declaration. + s.write('class $helperClassName{\n'); + s.write('final $structName _struct;\n'); + s.write('final int length;\n'); + s.write('$helperClassName(this._struct, this.length);\n'); + + // Override []= operator. + s.write('void operator []=(int index, $arrayType value) {\n'); + s.write('switch(index) {\n'); + for (var i = 0; i < length; i++) { + s.write('case $i:\n'); + s.write(' _struct.${elementNamePrefix}$i = value;\n'); + s.write(' break;\n'); + } + s.write('default:\n'); + s.write( + " throw RangeError('Index \$index must be in the range [0..${length - 1}].');"); + s.write('}\n'); + s.write('}\n'); + + // Override [] operator. + s.write('$arrayType operator [](int index) {\n'); + s.write('switch(index) {\n'); + for (var i = 0; i < length; i++) { + s.write('case $i:\n'); + s.write(' return _struct.${elementNamePrefix}$i;\n'); + } + s.write('default:\n'); + s.write( + " throw RangeError('Index \$index must be in the range [0..${length - 1}].');"); + s.write('}\n'); + s.write('}\n'); + + // Override toString(). + s.write('@override\n'); + s.write('String toString() {\n'); + s.write("if (length == 0) return '[]';\n"); + s.write("final sb = StringBuffer('[');\n"); + s.write('sb.write(this[0]);\n'); + s.write('for (var i = 1; i < length; i++) {\n'); + s.write(" sb.write(',');\n"); + s.write(' sb.write(this[i]);'); + s.write('}\n'); + s.write("sb.write(']');"); + s.write('return sb.toString();\n'); + s.write('}\n'); + + s.write('}\n\n'); + return s.toString(); + } +} diff --git a/lib/src/code_generator/type.dart b/lib/src/code_generator/type.dart new file mode 100644 index 00000000..b393d349 --- /dev/null +++ b/lib/src/code_generator/type.dart @@ -0,0 +1,165 @@ +// Copyright (c) 2020, the Dart project authors. Please see the AUTHORS file +// for details. All rights reserved. Use of this source code is governed by a +// BSD-style license that can be found in the LICENSE file. + +import 'package:meta/meta.dart'; + +import 'writer.dart'; + +class _SubType { + final String c; + final String dart; + + const _SubType({this.c, this.dart}); +} + +enum SupportedNativeType { + Void, + Char, + Int8, + Int16, + Int32, + Int64, + Uint8, + Uint16, + Uint32, + Uint64, + Float, + Double, + IntPtr, +} + +/// The basic types in which all types can be broadly classified into. +enum BroadType { + NativeType, + Pointer, + Struct, + NativeFunction, + + /// Stores its element type in NativeType as only those are supported. + ConstantArray, + + /// Used as a marker, so that functions/structs having these can exclude them. + Unimplemented, +} + +/// Type class for return types, variable types, etc. +class Type { + static const _primitives = { + SupportedNativeType.Void: _SubType(c: 'Void', dart: 'void'), + SupportedNativeType.Char: _SubType(c: 'Uint8', dart: 'int'), + SupportedNativeType.Int8: _SubType(c: 'Int8', dart: 'int'), + SupportedNativeType.Int16: _SubType(c: 'Int16', dart: 'int'), + SupportedNativeType.Int32: _SubType(c: 'Int32', dart: 'int'), + SupportedNativeType.Int64: _SubType(c: 'Int64', dart: 'int'), + SupportedNativeType.Uint8: _SubType(c: 'Uint8', dart: 'int'), + SupportedNativeType.Uint16: _SubType(c: 'Uint16', dart: 'int'), + SupportedNativeType.Uint32: _SubType(c: 'Uint32', dart: 'int'), + SupportedNativeType.Uint64: _SubType(c: 'Uint64', dart: 'int'), + SupportedNativeType.Float: _SubType(c: 'Float', dart: 'double'), + SupportedNativeType.Double: _SubType(c: 'Double', dart: 'double'), + SupportedNativeType.IntPtr: _SubType(c: 'IntPtr', dart: 'int'), + }; + + /// For providing name of Struct. + String structName; + + /// For providing name of nativeFunc. + String nativeFuncName; + + /// For providing [SupportedNativeType] only. + final SupportedNativeType nativeType; + + /// The BroadType of this Type. + final BroadType broadType; + + /// Child Type, e.g Pointer(Parent) to Int(Child). + final Type child; + + /// For ConstantArray type. + final int arrayLength; + final Type elementType; + + /// For storing cursor type info for an unimplemented type. + String unimplementedReason; + + Type._({ + @required this.broadType, + this.child, + this.structName, + this.nativeType, + this.nativeFuncName, + this.arrayLength, + this.elementType, + this.unimplementedReason, + }); + + factory Type.pointer(Type child) { + return Type._(broadType: BroadType.Pointer, child: child); + } + factory Type.struct(String structName) { + return Type._(broadType: BroadType.Struct, structName: structName); + } + factory Type.nativeFunc(String nativeFuncName) { + return Type._( + broadType: BroadType.NativeFunction, nativeFuncName: nativeFuncName); + } + factory Type.nativeType(SupportedNativeType nativeType) { + return Type._(broadType: BroadType.NativeType, nativeType: nativeType); + } + factory Type.constantArray(int arrayLength, Type elementType) { + return Type._(broadType: BroadType.ConstantArray, elementType: elementType); + } + factory Type.unimplemented(String reason) { + return Type._( + broadType: BroadType.Unimplemented, unimplementedReason: reason); + } + + /// Get base broad type for any type. + /// + /// E.g int** has base Broadtype as NativeType. + BroadType getBaseBroadType() { + if (broadType == BroadType.Pointer) { + return child.getBaseBroadType(); + } else { + return broadType; + } + } + + bool get isPrimitive => broadType == BroadType.NativeType; + + String getCType(Writer w) { + switch (broadType) { + case BroadType.NativeType: + return '${w.ffiLibraryPrefix}.${_primitives[nativeType].c}'; + case BroadType.Pointer: + return '${w.ffiLibraryPrefix}.Pointer<${child.getCType(w)}>'; + case BroadType.Struct: + return structName; + case BroadType.NativeFunction: + return '${w.ffiLibraryPrefix}.NativeFunction<${nativeFuncName}>'; + default: + throw Exception('cType unknown'); + } + } + + String getDartType(Writer w) { + switch (broadType) { + case BroadType.NativeType: + return _primitives[nativeType].dart; + case BroadType.Pointer: + return '${w.ffiLibraryPrefix}.Pointer<${child.getCType(w)}>'; + case BroadType.Struct: + return structName; + case BroadType.NativeFunction: + return '${w.ffiLibraryPrefix}.NativeFunction<${nativeFuncName}>'; + default: + throw Exception('dart type unknown for ${broadType.toString()}'); + } + } + + @override + String toString() { + return 'Type: ${broadType}'; + } +} diff --git a/lib/src/code_generator/typedef.dart b/lib/src/code_generator/typedef.dart new file mode 100644 index 00000000..ea9568f3 --- /dev/null +++ b/lib/src/code_generator/typedef.dart @@ -0,0 +1,54 @@ +// Copyright (c) 2020, the Dart project authors. Please see the AUTHORS file +// for details. All rights reserved. Use of this source code is governed by a +// BSD-style license that can be found in the LICENSE file. + +import 'package:meta/meta.dart'; + +import 'binding.dart'; +import 'binding_string.dart'; +import 'func.dart' show Parameter; +import 'type.dart'; +import 'writer.dart'; + +/// A simple typedef function for C functions, Expands to - +/// +/// ```dart +/// typedef $name = $returnType Function( +/// $parameter1..., +/// $parameter2..., +/// . +/// . +/// );` +/// ``` +/// Note: This doesn't bind with anything. +class TypedefC extends Binding { + final Type returnType; + final List parameters; + + TypedefC({ + @required String name, + String dartDoc, + @required this.returnType, + List parameters, + }) : parameters = parameters ?? [], + super(name: name, dartDoc: dartDoc); + + @override + BindingString toBindingString(Writer w) { + final s = StringBuffer(); + + if (dartDoc != null) { + s.write('/// '); + s.writeAll(dartDoc.split('\n'), '\n/// '); + s.write('\n'); + } + + s.write('typedef $name = ${returnType.getCType(w)} Function(\n'); + for (final p in parameters) { + s.write(' ${p.type.getCType(w)} ${p.name},\n'); + } + s.write(');\n\n'); + + return BindingString(type: BindingStringType.typeDef, string: s.toString()); + } +} diff --git a/lib/src/code_generator/writer.dart b/lib/src/code_generator/writer.dart new file mode 100644 index 00000000..cc4496ff --- /dev/null +++ b/lib/src/code_generator/writer.dart @@ -0,0 +1,64 @@ +// Copyright (c) 2020, the Dart project authors. Please see the AUTHORS file +// for details. All rights reserved. Use of this source code is governed by a +// BSD-style license that can be found in the LICENSE file. + +import 'binding_string.dart'; + +/// To store generated String bindings. +class Writer { + String header; + String dylibIdentifier; + String initFunctionIdentifier; + + /// dart:ffi library import prefix. + String ffiLibraryPrefix; + + final List _bindings = []; + + Writer({ + this.dylibIdentifier = '_dylib', + this.initFunctionIdentifier = 'init', + this.ffiLibraryPrefix = 'ffi', + }); + + String generate() { + final s = StringBuffer(); + + // Write header (if any) + if (header != null) { + s.write(header); + s.write('\n'); + } else { + // Write default header, in case none was provided. + s.write('''/// AUTO GENERATED FILE, DO NOT EDIT. +/// +/// Generated by `package:ffigen`. +'''); + } + + // Write neccesary imports. + s.write("import 'dart:ffi' as $ffiLibraryPrefix;\n"); + s.write('\n'); + + // Write dylib. + s.write('/// Holds the Dynamic library.\n'); + s.write('$ffiLibraryPrefix.DynamicLibrary ${dylibIdentifier};\n'); + s.write('\n'); + s.write('/// Initialises the Dynamic library.\n'); + s.write( + 'void $initFunctionIdentifier($ffiLibraryPrefix.DynamicLibrary dylib){\n'); + s.write(' ${dylibIdentifier} = dylib;\n'); + s.write('}\n'); + + // Write bindings. + for (final bs in _bindings) { + s.write(bs.string); + } + + return s.toString(); + } + + void addBindingString(BindingString b) { + _bindings.add(b); + } +} diff --git a/lib/src/config_provider.dart b/lib/src/config_provider.dart new file mode 100644 index 00000000..990e137d --- /dev/null +++ b/lib/src/config_provider.dart @@ -0,0 +1,8 @@ +// Copyright (c) 2020, the Dart project authors. Please see the AUTHORS file +// for details. All rights reserved. Use of this source code is governed by a +// BSD-style license that can be found in the LICENSE file. + +/// Creates config object used by other sub_modules. +library config_provider; + +export 'config_provider/config.dart'; diff --git a/lib/src/config_provider/config.dart b/lib/src/config_provider/config.dart new file mode 100644 index 00000000..89f55c20 --- /dev/null +++ b/lib/src/config_provider/config.dart @@ -0,0 +1,287 @@ +// Copyright (c) 2020, the Dart project authors. Please see the AUTHORS file +// for details. All rights reserved. Use of this source code is governed by a +// BSD-style license that can be found in the LICENSE file. + +import 'dart:io'; + +/// Validates the yaml input by the user, prints useful info for the user + +import 'package:ffigen/src/code_generator.dart'; +import 'package:ffigen/src/header_parser/type_extractor/cxtypekindmap.dart'; + +import 'package:logging/logging.dart'; +import 'package:meta/meta.dart'; +import 'package:path/path.dart' as path; +import 'package:yaml/yaml.dart'; + +import '../strings.dart' as strings; +import 'filter.dart'; +import 'spec_utils.dart'; + +var _logger = Logger('config_provider/config'); + +/// Provides configurations to other modules. +/// +/// Handles validation, extraction of confiurations from yaml file. +class Config { + /// output file name. + String output; + + /// libclang path (in accordance with the platform). + /// + /// File may have the following extensions - `.so` / `.dll` / `.dylib` + /// as extracted by configspec. + String libclang_dylib_path; + + /// Path to headers. + /// + /// This contains all the headers, after extraction from Globs. + List headers; + + /// Filter for headers. + HeaderFilter headerFilter; + + /// CommandLine Arguments to pass to clang_compiler. + List compilerOpts; + + /// Filter for functions. + Filter functionFilters; + + /// Filter for structs. + Filter structFilters; + + /// Filter for enumClass. + Filter enumClassFilters; + + /// If generated bindings should be sorted alphabetically. + bool sort; + + /// If typedef of supported types(int8_t) should be directly used. + bool useSupportedTypedefs; + + /// If tool should extract doc comment from bindings. + bool extractComments; + + /// Manually creating configurations. + /// + /// Use [Config.fromYaml] if extracting info from a yaml file. + /// Ensure that log printing is setup before using this. + Config.raw({ + this.output, + @required this.libclang_dylib_path, + @required this.headers, + this.headerFilter, + this.compilerOpts, + this.functionFilters, + this.structFilters, + this.enumClassFilters, + this.sort = false, + this.useSupportedTypedefs = true, + this.extractComments = true, + }); + + Config._(); + + /// Create config from Yaml map. + /// + /// Ensure that log printing is setup before using this. + factory Config.fromYaml(YamlMap map) { + final configspecs = Config._(); + _logger.finest('Config Map: ' + map.toString()); + + final specs = configspecs._getSpecs(); + + final result = configspecs._checkConfigs(map, specs); + if (!result) { + _logger.info('Please fix errors in Configurations and re-run the tool'); + exit(1); + } + + configspecs._extract(map, specs); + return configspecs; + } + + /// Validates Yaml according to given specs. + bool _checkConfigs(YamlMap map, Map specs) { + var _result = true; + for (final key in specs.keys) { + final spec = specs[key]; + if (spec.isRequired && !map.containsKey(key)) { + _logger.severe("Key '${key}' is required."); + _result = false; + } else if (map.containsKey(key)) { + _result = _result && spec.validator(key, map[key]); + } + } + // Warn about unknown keys. + for (final key in map.keys) { + if (!specs.containsKey(key)) { + _logger.warning("Unknown key '$key' found."); + } + } + + return _result; + } + + /// Extracts variables from Yaml according to given specs. + /// + /// Validation must be done beforehand, using [_checkConfigs]. + void _extract(YamlMap map, Map specs) { + for (final key in specs.keys) { + final spec = specs[key]; + if (map.containsKey(key)) { + spec.extractedResult(spec.extractor(map[key])); + } else { + spec.extractedResult(spec.defaultValue); + } + } + } + + /// Returns map of various specifications avaialble for our tool. + /// + /// Key: Name, Value: [Specification] + Map _getSpecs() { + return { + strings.output: Specification( + description: 'Output file name', + isRequired: true, + validator: outputValidator, + extractor: outputExtractor, + defaultValue: null, + extractedResult: (dynamic result) => output = result as String, + ), + strings.libclang_dylib_folder: Specification( + description: + 'Path to folder containing libclang dynamic library, used to parse C headers', + isRequired: false, + defaultValue: getDylibPath(Platform.script + .resolve(path.join('..', 'tool', 'wrapped_libclang')) + .toFilePath()), + validator: libclangDylibValidator, + extractor: libclangDylibExtractor, + extractedResult: (dynamic result) => + libclang_dylib_path = result as String, + ), + strings.headers: Specification>( + description: 'List of C headers to generate bindings of', + isRequired: true, + validator: headersValidator, + extractor: headersExtractor, + extractedResult: (dynamic result) => headers = result as List, + ), + strings.headerFilter: Specification( + description: 'Include/Exclude inclusion headers', + validator: headerFilterValidator, + extractor: headerFilterExtractor, + defaultValue: HeaderFilter(), + extractedResult: (dynamic result) { + return headerFilter = result as HeaderFilter; + }, + ), + strings.compilerOpts: Specification>( + description: 'Raw compiler options to pass to clang compiler', + isRequired: false, + validator: compilerOptsValidator, + extractor: compilerOptsExtractor, + defaultValue: null, + extractedResult: (dynamic result) => + compilerOpts = result as List, + ), + strings.functions: Specification( + description: 'Filter for functions', + isRequired: false, + validator: filterValidator, + extractor: filterExtractor, + defaultValue: null, + extractedResult: (dynamic result) => functionFilters = result as Filter, + ), + strings.structs: Specification( + description: 'Filter for Structs', + isRequired: false, + validator: filterValidator, + extractor: filterExtractor, + defaultValue: null, + extractedResult: (dynamic result) => structFilters = result as Filter, + ), + strings.enums: Specification( + description: 'Filter for enums', + isRequired: false, + validator: filterValidator, + extractor: filterExtractor, + defaultValue: null, + extractedResult: (dynamic result) => + enumClassFilters = result as Filter, + ), + strings.sizemap: Specification>( + description: 'map of types: byte size in int', + validator: sizemapValidator, + extractor: sizemapExtractor, + defaultValue: {}, + extractedResult: (dynamic result) { + final map = result as Map; + for (final key in map.keys) { + if (cxTypeKindToSupportedNativeTypes.containsKey(key)) { + cxTypeKindToSupportedNativeTypes[key] = map[key]; + } + } + }, + ), + strings.sort: Specification( + description: 'whether or not to sort the bindings alphabetically', + isRequired: false, + validator: booleanValidator, + extractor: booleanExtractor, + defaultValue: false, + extractedResult: (dynamic result) => sort = result as bool, + ), + strings.useSupportedTypedefs: Specification( + description: 'whether or not to directly map supported typedef by name', + isRequired: false, + validator: booleanValidator, + extractor: booleanExtractor, + defaultValue: true, + extractedResult: (dynamic result) => + useSupportedTypedefs = result as bool, + ), + strings.extractComments: Specification( + description: 'whether or not to extract comments from bindings', + isRequired: false, + validator: booleanValidator, + extractor: booleanExtractor, + defaultValue: true, + extractedResult: (dynamic result) => extractComments = result as bool, + ), + }; + } +} + +/// Represents a single specification in configurations. +/// +/// [E] is the return type of the extractedResult. +class Specification { + final String description; + final bool Function(String name, dynamic value) validator; + final E Function(dynamic map) extractor; + final E defaultValue; + final bool isRequired; + final void Function(dynamic result) extractedResult; + + Specification({ + @required this.extractedResult, + @required this.description, + @required this.validator, + @required this.extractor, + this.defaultValue, + this.isRequired = false, + }); +} + +class HeaderFilter { + Set includedInclusionHeaders; + Set excludedInclusionHeaders; + + HeaderFilter({ + this.includedInclusionHeaders = const {}, + this.excludedInclusionHeaders = const {}, + }); +} diff --git a/lib/src/config_provider/filter.dart b/lib/src/config_provider/filter.dart new file mode 100644 index 00000000..b35dc0b2 --- /dev/null +++ b/lib/src/config_provider/filter.dart @@ -0,0 +1,80 @@ +// Copyright (c) 2020, the Dart project authors. Please see the AUTHORS file +// for details. All rights reserved. Use of this source code is governed by a +// BSD-style license that can be found in the LICENSE file. + +/// A generic filter for filtering strings based on regexes and prefixes. +/// +/// Excludes override includes. +/// +/// User can provide fiters for functions, structs, enums and include/exclude +/// them using regexp and full name matching. +class Filter { + // matchers + List _includeMatchers = []; + Set _includeFull = {}; + List _excludeMatchers = []; + Set _excludeFull = {}; + + Filter({ + List includeMatchers, + List includeFull, + List excludeMatchers, + List excludeFull, + }) { + if (includeMatchers != null) { + _includeMatchers = + includeMatchers.map((e) => RegExp(e, dotAll: true)).toList(); + } + if (includeFull != null) { + _includeFull = includeFull.map((e) => e).toSet(); + } + if (excludeMatchers != null) { + _excludeMatchers = + excludeMatchers.map((e) => RegExp(e, dotAll: true)).toList(); + } + if (excludeFull != null) { + _excludeFull = excludeFull.map((e) => e).toSet(); + } + } + + /// Checks if a name is allowed by a filter. + bool shouldInclude(String name) { + if (_excludeFull.contains(name)) { + return false; + } + + for (final em in _excludeMatchers) { + if (em.firstMatch(name)?.end == name.length) { + return false; + } + } + + if (_includeFull.contains(name)) { + return true; + } + + for (final im in _includeMatchers) { + if (im.firstMatch(name)?.end == name.length) { + return true; + } + } + + // If user has provided 'include' field in the filter, then default + // matching is false. + if (_includeMatchers.isNotEmpty || _includeFull.isNotEmpty) { + return false; + } else { + return true; + } + } + + @override + String toString() { + return ''' (includeFull, includeMatchers, excludeFull, excludeMatchers) +$_includeFull +$_includeMatchers +$_excludeFull +$_excludeMatchers + '''; + } +} diff --git a/lib/src/config_provider/spec_utils.dart b/lib/src/config_provider/spec_utils.dart new file mode 100644 index 00000000..683d53dd --- /dev/null +++ b/lib/src/config_provider/spec_utils.dart @@ -0,0 +1,241 @@ +// Copyright (c) 2020, the Dart project authors. Please see the AUTHORS file +// for details. All rights reserved. Use of this source code is governed by a +// BSD-style license that can be found in the LICENSE file. + +import 'dart:io'; + +import 'package:ffigen/src/code_generator.dart'; +import 'package:glob/glob.dart'; +import 'package:logging/logging.dart'; +import 'package:path/path.dart' as p; +import 'package:yaml/yaml.dart'; + +import '../strings.dart' as strings; +import './config.dart'; +import 'filter.dart'; + +var _logger = Logger('config_provider/utils'); + +bool booleanExtractor(dynamic value) => value as bool; + +bool booleanValidator(String name, dynamic value) { + if (value is! bool) { + _logger.severe("Expected value of key '$name' to be a bool."); + return false; + } else { + return true; + } +} + +Map sizemapExtractor(dynamic yamlConfig) { + final resultMap = {}; + final sizemap = yamlConfig as YamlMap; + if (sizemap != null) { + for (final typeName in strings.sizemap_native_mapping.keys) { + if (sizemap.containsKey(typeName)) { + final cxTypeInt = strings.sizemap_native_mapping[typeName]; + final byteSize = sizemap[typeName] as int; + resultMap[cxTypeInt] = nativeSupportedType(byteSize, + signed: typeName.contains('unsigned') ? false : true); + } + } + } + return resultMap; +} + +bool sizemapValidator(String name, dynamic yamlConfig) { + if (yamlConfig is! YamlMap) { + _logger.severe("Expected value of key '$name' to be a Map."); + return false; + } + for (final key in (yamlConfig as YamlMap).keys) { + if (!strings.sizemap_native_mapping.containsKey(key)) { + _logger.warning("Unknown subkey '$key' in '$name'."); + } + } + + return true; +} + +List compilerOptsExtractor(dynamic value) => + (value as String)?.split(' '); + +bool compilerOptsValidator(String name, dynamic value) { + if (value is! String) { + _logger.severe("Expected value of key '$name' to be a string."); + return false; + } else { + return true; + } +} + +HeaderFilter headerFilterExtractor(dynamic yamlConfig) { + final includedInclusionHeaders = {}; + final excludedInclusionHeaders = {}; + + final headerFilter = yamlConfig as YamlMap; + if (headerFilter != null) { + // Add include/excluded header-filter from Yaml. + final include = headerFilter[strings.include] as YamlList; + include?.cast()?.forEach(includedInclusionHeaders.add); + + final exclude = headerFilter[strings.exclude] as YamlList; + exclude?.cast()?.forEach(excludedInclusionHeaders.add); + } + + return HeaderFilter( + includedInclusionHeaders: includedInclusionHeaders, + excludedInclusionHeaders: excludedInclusionHeaders, + ); +} + +bool headerFilterValidator(String name, dynamic value) { + if (value is! YamlMap) { + _logger.severe("Expected value of key '$name' to be a Map."); + return false; + } else { + return true; + } +} + +List headersExtractor(dynamic yamlConfig) { + final headers = []; + for (final h in (yamlConfig as YamlList)) { + final headerGlob = h as String; + // Add file directly to header if it's not a Glob but a File. + if (File(headerGlob).existsSync()) { + headers.add(headerGlob); + _logger.fine('Adding header/file: $headerGlob'); + } else { + final glob = Glob(headerGlob); + for (final file in glob.listSync(followLinks: true)) { + headers.add(file.path); + _logger.fine('Adding header/file: ${file.path}'); + } + } + } + return headers; +} + +bool headersValidator(String name, dynamic value) { + if (value is! YamlList) { + _logger.severe( + "Expected value of key '${strings.headers}' to be a List of String."); + return false; + } else { + return true; + } +} + +String libclangDylibExtractor(dynamic value) => getDylibPath(value as String); + +bool libclangDylibValidator(String name, dynamic value) { + if (value is! String) { + _logger.severe("Expected value of key '$name' to be a string."); + return false; + } else { + final dylibPath = getDylibPath(value as String); + if (!File(dylibPath).existsSync()) { + _logger.severe( + 'Dynamic library: $dylibPath does not exist or is corrupt, input folder: $value.'); + return false; + } else { + return true; + } + } +} + +String getDylibPath(String dylibParentFoler) { + String dylibPath; + if (Platform.isMacOS) { + dylibPath = p.join(dylibParentFoler, strings.libclang_dylib_macos); + } else if (Platform.isWindows) { + // Fix path for windows if '/' is used as seperator instead of '\' + // because our examples input path like this. + final newValue = dylibParentFoler.replaceAll('/', r'\'); + dylibPath = p.join(newValue, strings.libclang_dylib_windows); + } else { + dylibPath = p.join(dylibParentFoler, strings.libclang_dylib_linux); + } + return dylibPath; +} + +String outputExtractor(dynamic value) => value as String; + +bool outputValidator(String name, dynamic value) { + if (value is String) { + return true; + } else { + _logger.severe("Expected value of key '${strings.output}' to be a String."); + return false; + } +} + +Filter filterExtractor(dynamic yamlMap) { + List includeMatchers, includeFull, excludeMatchers, excludeFull; + + final include = yamlMap[strings.include] as YamlMap; + if (include != null) { + includeMatchers = (include[strings.matches] as YamlList)?.cast(); + includeFull = (include[strings.names] as YamlList)?.cast(); + } + + final exclude = yamlMap[strings.exclude] as YamlMap; + if (exclude != null) { + excludeMatchers = (exclude[strings.matches] as YamlList)?.cast(); + excludeFull = (exclude[strings.names] as YamlList)?.cast(); + } + + return Filter( + includeMatchers: includeMatchers, + includeFull: includeFull, + excludeMatchers: excludeMatchers, + excludeFull: excludeFull, + ); +} + +bool filterValidator(String name, dynamic value) { + var _result = true; + if (value is YamlMap) { + for (final key in value.keys) { + if (key == strings.include || key == strings.exclude) { + if (value[key] is! YamlMap) { + _logger.severe("Expected '$name -> $key' to be a Map."); + } + for (final subkey in value[key].keys) { + if (subkey == strings.matches || subkey == strings.names) { + if (value[key][subkey] is! YamlList) { + _logger.severe("Expected '$name -> $key -> $subkey' to be a List."); + _result = false; + } + } else { + _logger.severe("Unknown key '$subkey' in '$name -> $key'."); + } + } + } else { + _logger.severe("Unknown key '$key' in '$name'."); + _result = false; + } + } + } else { + _logger.severe("Expected value '$name' to be a Map."); + _result = false; + } + return _result; +} + +SupportedNativeType nativeSupportedType(int value, {bool signed = true}) { + switch (value) { + case 1: + return signed ? SupportedNativeType.Int8 : SupportedNativeType.Uint8; + case 2: + return signed ? SupportedNativeType.Int16 : SupportedNativeType.Uint16; + case 4: + return signed ? SupportedNativeType.Int32 : SupportedNativeType.Uint32; + case 8: + return signed ? SupportedNativeType.Int64 : SupportedNativeType.Uint64; + default: + throw Exception( + 'Unsupported value given to sizemap, Allowed values for sizes are: 1, 2, 4, 8'); + } +} diff --git a/lib/src/header_parser.dart b/lib/src/header_parser.dart new file mode 100644 index 00000000..e4dc2c94 --- /dev/null +++ b/lib/src/header_parser.dart @@ -0,0 +1,10 @@ +// Copyright (c) 2020, the Dart project authors. Please see the AUTHORS file +// for details. All rights reserved. Use of this source code is governed by a +// BSD-style license that can be found in the LICENSE file. + +/// Generates a [Library] (code_generator) +/// +/// Parses the header files AST using clang_bindings. +library header_parser; + +export 'header_parser/parser.dart' show parse; diff --git a/lib/src/header_parser/clang_bindings/clang_bindings.dart b/lib/src/header_parser/clang_bindings/clang_bindings.dart new file mode 100644 index 00000000..f7019710 --- /dev/null +++ b/lib/src/header_parser/clang_bindings/clang_bindings.dart @@ -0,0 +1,1447 @@ +/// AUTO GENERATED FILE, DO NOT EDIT. +/// +/// Generated by `package:ffigen`. +import 'dart:ffi' as ffi; + +/// Holds the Dynamic library. +ffi.DynamicLibrary _dylib; + +/// Initialises the Dynamic library. +void init(ffi.DynamicLibrary dylib) { + _dylib = dylib; +} + +/// Describes how the traversal of the children of a particular cursor should proceed after visiting a particular child cursor. +class CXChildVisitResult { + static const int CXChildVisit_Break = 0; + static const int CXChildVisit_Continue = 1; + static const int CXChildVisit_Recurse = 2; +} + +/// A cursor representing some element in the abstract syntax tree for a translation unit. +class CXCursor extends ffi.Struct { + @ffi.Int32() + int kind; + + @ffi.Int32() + int xdata; + + ffi.Pointer _data_item_0; + ffi.Pointer _data_item_1; + ffi.Pointer _data_item_2; + + /// helper for array, supports `[]` operator + _ArrayHelper_CXCursor_data get data => _ArrayHelper_CXCursor_data(this, 3); +} + +/// Helper for array data in struct CXCursor +class _ArrayHelper_CXCursor_data { + final CXCursor _struct; + final int length; + _ArrayHelper_CXCursor_data(this._struct, this.length); + void operator []=(int index, ffi.Pointer value) { + switch (index) { + case 0: + _struct._data_item_0 = value; + break; + case 1: + _struct._data_item_1 = value; + break; + case 2: + _struct._data_item_2 = value; + break; + default: + throw RangeError('Index $index must be in the range [0..2].'); + } + } + + ffi.Pointer operator [](int index) { + switch (index) { + case 0: + return _struct._data_item_0; + case 1: + return _struct._data_item_1; + case 2: + return _struct._data_item_2; + default: + throw RangeError('Index $index must be in the range [0..2].'); + } + } + + @override + String toString() { + if (length == 0) return '[]'; + final sb = StringBuffer('['); + sb.write(this[0]); + for (var i = 1; i < length; i++) { + sb.write(','); + sb.write(this[i]); + } + sb.write(']'); + return sb.toString(); + } +} + +/// Describes the kind of entity that a cursor refers to. +class CXCursorKind { + static const int CXCursor_UnexposedDecl = 1; + static const int CXCursor_StructDecl = 2; + static const int CXCursor_UnionDecl = 3; + static const int CXCursor_ClassDecl = 4; + static const int CXCursor_EnumDecl = 5; + static const int CXCursor_FieldDecl = 6; + static const int CXCursor_EnumConstantDecl = 7; + static const int CXCursor_FunctionDecl = 8; + static const int CXCursor_VarDecl = 9; + static const int CXCursor_ParmDecl = 10; + static const int CXCursor_ObjCInterfaceDecl = 11; + static const int CXCursor_ObjCCategoryDecl = 12; + static const int CXCursor_ObjCProtocolDecl = 13; + static const int CXCursor_ObjCPropertyDecl = 14; + static const int CXCursor_ObjCIvarDecl = 15; + static const int CXCursor_ObjCInstanceMethodDecl = 16; + static const int CXCursor_ObjCClassMethodDecl = 17; + static const int CXCursor_ObjCImplementationDecl = 18; + static const int CXCursor_ObjCCategoryImplDecl = 19; + static const int CXCursor_TypedefDecl = 20; + static const int CXCursor_CXXMethod = 21; + static const int CXCursor_Namespace = 22; + static const int CXCursor_LinkageSpec = 23; + static const int CXCursor_Constructor = 24; + static const int CXCursor_Destructor = 25; + static const int CXCursor_ConversionFunction = 26; + static const int CXCursor_TemplateTypeParameter = 27; + static const int CXCursor_NonTypeTemplateParameter = 28; + static const int CXCursor_TemplateTemplateParameter = 29; + static const int CXCursor_FunctionTemplate = 30; + static const int CXCursor_ClassTemplate = 31; + static const int CXCursor_ClassTemplatePartialSpecialization = 32; + static const int CXCursor_NamespaceAlias = 33; + static const int CXCursor_UsingDirective = 34; + static const int CXCursor_UsingDeclaration = 35; + static const int CXCursor_TypeAliasDecl = 36; + static const int CXCursor_ObjCSynthesizeDecl = 37; + static const int CXCursor_ObjCDynamicDecl = 38; + static const int CXCursor_CXXAccessSpecifier = 39; + static const int CXCursor_FirstDecl = 1; + static const int CXCursor_LastDecl = 39; + static const int CXCursor_FirstRef = 40; + static const int CXCursor_ObjCSuperClassRef = 40; + static const int CXCursor_ObjCProtocolRef = 41; + static const int CXCursor_ObjCClassRef = 42; + static const int CXCursor_TypeRef = 43; + static const int CXCursor_CXXBaseSpecifier = 44; + static const int CXCursor_TemplateRef = 45; + static const int CXCursor_NamespaceRef = 46; + static const int CXCursor_MemberRef = 47; + static const int CXCursor_LabelRef = 48; + static const int CXCursor_OverloadedDeclRef = 49; + static const int CXCursor_VariableRef = 50; + static const int CXCursor_LastRef = 50; + static const int CXCursor_FirstInvalid = 70; + static const int CXCursor_InvalidFile = 70; + static const int CXCursor_NoDeclFound = 71; + static const int CXCursor_NotImplemented = 72; + static const int CXCursor_InvalidCode = 73; + static const int CXCursor_LastInvalid = 73; + static const int CXCursor_FirstExpr = 100; + static const int CXCursor_UnexposedExpr = 100; + static const int CXCursor_DeclRefExpr = 101; + static const int CXCursor_MemberRefExpr = 102; + static const int CXCursor_CallExpr = 103; + static const int CXCursor_ObjCMessageExpr = 104; + static const int CXCursor_BlockExpr = 105; + static const int CXCursor_IntegerLiteral = 106; + static const int CXCursor_FloatingLiteral = 107; + static const int CXCursor_ImaginaryLiteral = 108; + static const int CXCursor_StringLiteral = 109; + static const int CXCursor_CharacterLiteral = 110; + static const int CXCursor_ParenExpr = 111; + static const int CXCursor_UnaryOperator = 112; + static const int CXCursor_ArraySubscriptExpr = 113; + static const int CXCursor_BinaryOperator = 114; + static const int CXCursor_CompoundAssignOperator = 115; + static const int CXCursor_ConditionalOperator = 116; + static const int CXCursor_CStyleCastExpr = 117; + static const int CXCursor_CompoundLiteralExpr = 118; + static const int CXCursor_InitListExpr = 119; + static const int CXCursor_AddrLabelExpr = 120; + static const int CXCursor_StmtExpr = 121; + static const int CXCursor_GenericSelectionExpr = 122; + static const int CXCursor_GNUNullExpr = 123; + static const int CXCursor_CXXStaticCastExpr = 124; + static const int CXCursor_CXXDynamicCastExpr = 125; + static const int CXCursor_CXXReinterpretCastExpr = 126; + static const int CXCursor_CXXConstCastExpr = 127; + static const int CXCursor_CXXFunctionalCastExpr = 128; + static const int CXCursor_CXXTypeidExpr = 129; + static const int CXCursor_CXXBoolLiteralExpr = 130; + static const int CXCursor_CXXNullPtrLiteralExpr = 131; + static const int CXCursor_CXXThisExpr = 132; + static const int CXCursor_CXXThrowExpr = 133; + static const int CXCursor_CXXNewExpr = 134; + static const int CXCursor_CXXDeleteExpr = 135; + static const int CXCursor_UnaryExpr = 136; + static const int CXCursor_ObjCStringLiteral = 137; + static const int CXCursor_ObjCEncodeExpr = 138; + static const int CXCursor_ObjCSelectorExpr = 139; + static const int CXCursor_ObjCProtocolExpr = 140; + static const int CXCursor_ObjCBridgedCastExpr = 141; + static const int CXCursor_PackExpansionExpr = 142; + static const int CXCursor_SizeOfPackExpr = 143; + static const int CXCursor_LambdaExpr = 144; + static const int CXCursor_ObjCBoolLiteralExpr = 145; + static const int CXCursor_ObjCSelfExpr = 146; + static const int CXCursor_OMPArraySectionExpr = 147; + static const int CXCursor_ObjCAvailabilityCheckExpr = 148; + static const int CXCursor_FixedPointLiteral = 149; + static const int CXCursor_LastExpr = 149; + static const int CXCursor_FirstStmt = 200; + static const int CXCursor_UnexposedStmt = 200; + static const int CXCursor_LabelStmt = 201; + static const int CXCursor_CompoundStmt = 202; + static const int CXCursor_CaseStmt = 203; + static const int CXCursor_DefaultStmt = 204; + static const int CXCursor_IfStmt = 205; + static const int CXCursor_SwitchStmt = 206; + static const int CXCursor_WhileStmt = 207; + static const int CXCursor_DoStmt = 208; + static const int CXCursor_ForStmt = 209; + static const int CXCursor_GotoStmt = 210; + static const int CXCursor_IndirectGotoStmt = 211; + static const int CXCursor_ContinueStmt = 212; + static const int CXCursor_BreakStmt = 213; + static const int CXCursor_ReturnStmt = 214; + static const int CXCursor_GCCAsmStmt = 215; + static const int CXCursor_AsmStmt = 215; + static const int CXCursor_ObjCAtTryStmt = 216; + static const int CXCursor_ObjCAtCatchStmt = 217; + static const int CXCursor_ObjCAtFinallyStmt = 218; + static const int CXCursor_ObjCAtThrowStmt = 219; + static const int CXCursor_ObjCAtSynchronizedStmt = 220; + static const int CXCursor_ObjCAutoreleasePoolStmt = 221; + static const int CXCursor_ObjCForCollectionStmt = 222; + static const int CXCursor_CXXCatchStmt = 223; + static const int CXCursor_CXXTryStmt = 224; + static const int CXCursor_CXXForRangeStmt = 225; + static const int CXCursor_SEHTryStmt = 226; + static const int CXCursor_SEHExceptStmt = 227; + static const int CXCursor_SEHFinallyStmt = 228; + static const int CXCursor_MSAsmStmt = 229; + static const int CXCursor_NullStmt = 230; + static const int CXCursor_DeclStmt = 231; + static const int CXCursor_OMPParallelDirective = 232; + static const int CXCursor_OMPSimdDirective = 233; + static const int CXCursor_OMPForDirective = 234; + static const int CXCursor_OMPSectionsDirective = 235; + static const int CXCursor_OMPSectionDirective = 236; + static const int CXCursor_OMPSingleDirective = 237; + static const int CXCursor_OMPParallelForDirective = 238; + static const int CXCursor_OMPParallelSectionsDirective = 239; + static const int CXCursor_OMPTaskDirective = 240; + static const int CXCursor_OMPMasterDirective = 241; + static const int CXCursor_OMPCriticalDirective = 242; + static const int CXCursor_OMPTaskyieldDirective = 243; + static const int CXCursor_OMPBarrierDirective = 244; + static const int CXCursor_OMPTaskwaitDirective = 245; + static const int CXCursor_OMPFlushDirective = 246; + static const int CXCursor_SEHLeaveStmt = 247; + static const int CXCursor_OMPOrderedDirective = 248; + static const int CXCursor_OMPAtomicDirective = 249; + static const int CXCursor_OMPForSimdDirective = 250; + static const int CXCursor_OMPParallelForSimdDirective = 251; + static const int CXCursor_OMPTargetDirective = 252; + static const int CXCursor_OMPTeamsDirective = 253; + static const int CXCursor_OMPTaskgroupDirective = 254; + static const int CXCursor_OMPCancellationPointDirective = 255; + static const int CXCursor_OMPCancelDirective = 256; + static const int CXCursor_OMPTargetDataDirective = 257; + static const int CXCursor_OMPTaskLoopDirective = 258; + static const int CXCursor_OMPTaskLoopSimdDirective = 259; + static const int CXCursor_OMPDistributeDirective = 260; + static const int CXCursor_OMPTargetEnterDataDirective = 261; + static const int CXCursor_OMPTargetExitDataDirective = 262; + static const int CXCursor_OMPTargetParallelDirective = 263; + static const int CXCursor_OMPTargetParallelForDirective = 264; + static const int CXCursor_OMPTargetUpdateDirective = 265; + static const int CXCursor_OMPDistributeParallelForDirective = 266; + static const int CXCursor_OMPDistributeParallelForSimdDirective = 267; + static const int CXCursor_OMPDistributeSimdDirective = 268; + static const int CXCursor_OMPTargetParallelForSimdDirective = 269; + static const int CXCursor_OMPTargetSimdDirective = 270; + static const int CXCursor_OMPTeamsDistributeDirective = 271; + static const int CXCursor_OMPTeamsDistributeSimdDirective = 272; + static const int CXCursor_OMPTeamsDistributeParallelForSimdDirective = 273; + static const int CXCursor_OMPTeamsDistributeParallelForDirective = 274; + static const int CXCursor_OMPTargetTeamsDirective = 275; + static const int CXCursor_OMPTargetTeamsDistributeDirective = 276; + static const int CXCursor_OMPTargetTeamsDistributeParallelForDirective = 277; + static const int CXCursor_OMPTargetTeamsDistributeParallelForSimdDirective = + 278; + static const int CXCursor_OMPTargetTeamsDistributeSimdDirective = 279; + static const int CXCursor_BuiltinBitCastExpr = 280; + static const int CXCursor_OMPMasterTaskLoopDirective = 281; + static const int CXCursor_OMPParallelMasterTaskLoopDirective = 282; + static const int CXCursor_OMPMasterTaskLoopSimdDirective = 283; + static const int CXCursor_OMPParallelMasterTaskLoopSimdDirective = 284; + static const int CXCursor_OMPParallelMasterDirective = 285; + static const int CXCursor_LastStmt = 285; + static const int CXCursor_TranslationUnit = 300; + static const int CXCursor_FirstAttr = 400; + static const int CXCursor_UnexposedAttr = 400; + static const int CXCursor_IBActionAttr = 401; + static const int CXCursor_IBOutletAttr = 402; + static const int CXCursor_IBOutletCollectionAttr = 403; + static const int CXCursor_CXXFinalAttr = 404; + static const int CXCursor_CXXOverrideAttr = 405; + static const int CXCursor_AnnotateAttr = 406; + static const int CXCursor_AsmLabelAttr = 407; + static const int CXCursor_PackedAttr = 408; + static const int CXCursor_PureAttr = 409; + static const int CXCursor_ConstAttr = 410; + static const int CXCursor_NoDuplicateAttr = 411; + static const int CXCursor_CUDAConstantAttr = 412; + static const int CXCursor_CUDADeviceAttr = 413; + static const int CXCursor_CUDAGlobalAttr = 414; + static const int CXCursor_CUDAHostAttr = 415; + static const int CXCursor_CUDASharedAttr = 416; + static const int CXCursor_VisibilityAttr = 417; + static const int CXCursor_DLLExport = 418; + static const int CXCursor_DLLImport = 419; + static const int CXCursor_NSReturnsRetained = 420; + static const int CXCursor_NSReturnsNotRetained = 421; + static const int CXCursor_NSReturnsAutoreleased = 422; + static const int CXCursor_NSConsumesSelf = 423; + static const int CXCursor_NSConsumed = 424; + static const int CXCursor_ObjCException = 425; + static const int CXCursor_ObjCNSObject = 426; + static const int CXCursor_ObjCIndependentClass = 427; + static const int CXCursor_ObjCPreciseLifetime = 428; + static const int CXCursor_ObjCReturnsInnerPointer = 429; + static const int CXCursor_ObjCRequiresSuper = 430; + static const int CXCursor_ObjCRootClass = 431; + static const int CXCursor_ObjCSubclassingRestricted = 432; + static const int CXCursor_ObjCExplicitProtocolImpl = 433; + static const int CXCursor_ObjCDesignatedInitializer = 434; + static const int CXCursor_ObjCRuntimeVisible = 435; + static const int CXCursor_ObjCBoxable = 436; + static const int CXCursor_FlagEnum = 437; + static const int CXCursor_ConvergentAttr = 438; + static const int CXCursor_WarnUnusedAttr = 439; + static const int CXCursor_WarnUnusedResultAttr = 440; + static const int CXCursor_AlignedAttr = 441; + static const int CXCursor_LastAttr = 441; + static const int CXCursor_PreprocessingDirective = 500; + static const int CXCursor_MacroDefinition = 501; + static const int CXCursor_MacroExpansion = 502; + static const int CXCursor_MacroInstantiation = 502; + static const int CXCursor_InclusionDirective = 503; + static const int CXCursor_FirstPreprocessing = 500; + static const int CXCursor_LastPreprocessing = 503; + static const int CXCursor_ModuleImportDecl = 600; + static const int CXCursor_TypeAliasTemplateDecl = 601; + static const int CXCursor_StaticAssert = 602; + static const int CXCursor_FriendDecl = 603; + static const int CXCursor_FirstExtraDecl = 600; + static const int CXCursor_LastExtraDecl = 603; + static const int CXCursor_OverloadCandidate = 700; +} + +/// Options to control the display of diagnostics. +class CXDiagnosticDisplayOptions { + static const int CXDiagnostic_DisplaySourceLocation = 1; + static const int CXDiagnostic_DisplayColumn = 2; + static const int CXDiagnostic_DisplaySourceRanges = 4; + static const int CXDiagnostic_DisplayOption = 8; + static const int CXDiagnostic_DisplayCategoryId = 16; + static const int CXDiagnostic_DisplayCategoryName = 32; +} + +/// Identifies a specific source location within a translation unit. +class CXSourceLocation extends ffi.Struct { + ffi.Pointer _ptr_data_item_0; + ffi.Pointer _ptr_data_item_1; + ffi.Pointer _ptr_data_item_2; + + /// helper for array, supports `[]` operator + _ArrayHelper_CXSourceLocation_ptr_data get ptr_data => + _ArrayHelper_CXSourceLocation_ptr_data(this, 3); + @ffi.Uint32() + int int_data; +} + +/// Helper for array ptr_data in struct CXSourceLocation +class _ArrayHelper_CXSourceLocation_ptr_data { + final CXSourceLocation _struct; + final int length; + _ArrayHelper_CXSourceLocation_ptr_data(this._struct, this.length); + void operator []=(int index, ffi.Pointer value) { + switch (index) { + case 0: + _struct._ptr_data_item_0 = value; + break; + case 1: + _struct._ptr_data_item_1 = value; + break; + case 2: + _struct._ptr_data_item_2 = value; + break; + default: + throw RangeError('Index $index must be in the range [0..2].'); + } + } + + ffi.Pointer operator [](int index) { + switch (index) { + case 0: + return _struct._ptr_data_item_0; + case 1: + return _struct._ptr_data_item_1; + case 2: + return _struct._ptr_data_item_2; + default: + throw RangeError('Index $index must be in the range [0..2].'); + } + } + + @override + String toString() { + if (length == 0) return '[]'; + final sb = StringBuffer('['); + sb.write(this[0]); + for (var i = 1; i < length; i++) { + sb.write(','); + sb.write(this[i]); + } + sb.write(']'); + return sb.toString(); + } +} + +/// A character string. +class CXString extends ffi.Struct { + ffi.Pointer data; + + @ffi.Uint32() + int private_flags; +} + +class CXTranslationUnitImpl extends ffi.Struct {} + +/// Flags that control the creation of translation units. +class CXTranslationUnit_Flags { + static const int CXTranslationUnit_None = 0; + static const int CXTranslationUnit_DetailedPreprocessingRecord = 1; + static const int CXTranslationUnit_Incomplete = 2; + static const int CXTranslationUnit_PrecompiledPreamble = 4; + static const int CXTranslationUnit_CacheCompletionResults = 8; + static const int CXTranslationUnit_ForSerialization = 16; + static const int CXTranslationUnit_CXXChainedPCH = 32; + static const int CXTranslationUnit_SkipFunctionBodies = 64; + static const int CXTranslationUnit_IncludeBriefCommentsInCodeCompletion = 128; + static const int CXTranslationUnit_CreatePreambleOnFirstParse = 256; + static const int CXTranslationUnit_KeepGoing = 512; + static const int CXTranslationUnit_SingleFileParse = 1024; + static const int CXTranslationUnit_LimitSkipFunctionBodiesToPreamble = 2048; + static const int CXTranslationUnit_IncludeAttributedTypes = 4096; + static const int CXTranslationUnit_VisitImplicitAttributes = 8192; + static const int CXTranslationUnit_IgnoreNonErrorsFromIncludedFiles = 16384; + static const int CXTranslationUnit_RetainExcludedConditionalBlocks = 32768; +} + +/// The type of an element in the abstract syntax tree. +class CXType extends ffi.Struct { + @ffi.Int32() + int kind; + + ffi.Pointer _data_item_0; + ffi.Pointer _data_item_1; + ffi.Pointer _data_item_2; + + /// helper for array, supports `[]` operator + _ArrayHelper_CXType_data get data => _ArrayHelper_CXType_data(this, 3); +} + +/// Helper for array data in struct CXType +class _ArrayHelper_CXType_data { + final CXType _struct; + final int length; + _ArrayHelper_CXType_data(this._struct, this.length); + void operator []=(int index, ffi.Pointer value) { + switch (index) { + case 0: + _struct._data_item_0 = value; + break; + case 1: + _struct._data_item_1 = value; + break; + case 2: + _struct._data_item_2 = value; + break; + default: + throw RangeError('Index $index must be in the range [0..2].'); + } + } + + ffi.Pointer operator [](int index) { + switch (index) { + case 0: + return _struct._data_item_0; + case 1: + return _struct._data_item_1; + case 2: + return _struct._data_item_2; + default: + throw RangeError('Index $index must be in the range [0..2].'); + } + } + + @override + String toString() { + if (length == 0) return '[]'; + final sb = StringBuffer('['); + sb.write(this[0]); + for (var i = 1; i < length; i++) { + sb.write(','); + sb.write(this[i]); + } + sb.write(']'); + return sb.toString(); + } +} + +/// Describes the kind of type +class CXTypeKind { + static const int CXType_Invalid = 0; + static const int CXType_Unexposed = 1; + static const int CXType_Void = 2; + static const int CXType_Bool = 3; + static const int CXType_Char_U = 4; + static const int CXType_UChar = 5; + static const int CXType_Char16 = 6; + static const int CXType_Char32 = 7; + static const int CXType_UShort = 8; + static const int CXType_UInt = 9; + static const int CXType_ULong = 10; + static const int CXType_ULongLong = 11; + static const int CXType_UInt128 = 12; + static const int CXType_Char_S = 13; + static const int CXType_SChar = 14; + static const int CXType_WChar = 15; + static const int CXType_Short = 16; + static const int CXType_Int = 17; + static const int CXType_Long = 18; + static const int CXType_LongLong = 19; + static const int CXType_Int128 = 20; + static const int CXType_Float = 21; + static const int CXType_Double = 22; + static const int CXType_LongDouble = 23; + static const int CXType_NullPtr = 24; + static const int CXType_Overload = 25; + static const int CXType_Dependent = 26; + static const int CXType_ObjCId = 27; + static const int CXType_ObjCClass = 28; + static const int CXType_ObjCSel = 29; + static const int CXType_Float128 = 30; + static const int CXType_Half = 31; + static const int CXType_Float16 = 32; + static const int CXType_ShortAccum = 33; + static const int CXType_Accum = 34; + static const int CXType_LongAccum = 35; + static const int CXType_UShortAccum = 36; + static const int CXType_UAccum = 37; + static const int CXType_ULongAccum = 38; + static const int CXType_FirstBuiltin = 2; + static const int CXType_LastBuiltin = 38; + static const int CXType_Complex = 100; + static const int CXType_Pointer = 101; + static const int CXType_BlockPointer = 102; + static const int CXType_LValueReference = 103; + static const int CXType_RValueReference = 104; + static const int CXType_Record = 105; + static const int CXType_Enum = 106; + static const int CXType_Typedef = 107; + static const int CXType_ObjCInterface = 108; + static const int CXType_ObjCObjectPointer = 109; + static const int CXType_FunctionNoProto = 110; + static const int CXType_FunctionProto = 111; + static const int CXType_ConstantArray = 112; + static const int CXType_Vector = 113; + static const int CXType_IncompleteArray = 114; + static const int CXType_VariableArray = 115; + static const int CXType_DependentSizedArray = 116; + static const int CXType_MemberPointer = 117; + static const int CXType_Auto = 118; + static const int CXType_Elaborated = 119; + static const int CXType_Pipe = 120; + static const int CXType_OCLImage1dRO = 121; + static const int CXType_OCLImage1dArrayRO = 122; + static const int CXType_OCLImage1dBufferRO = 123; + static const int CXType_OCLImage2dRO = 124; + static const int CXType_OCLImage2dArrayRO = 125; + static const int CXType_OCLImage2dDepthRO = 126; + static const int CXType_OCLImage2dArrayDepthRO = 127; + static const int CXType_OCLImage2dMSAARO = 128; + static const int CXType_OCLImage2dArrayMSAARO = 129; + static const int CXType_OCLImage2dMSAADepthRO = 130; + static const int CXType_OCLImage2dArrayMSAADepthRO = 131; + static const int CXType_OCLImage3dRO = 132; + static const int CXType_OCLImage1dWO = 133; + static const int CXType_OCLImage1dArrayWO = 134; + static const int CXType_OCLImage1dBufferWO = 135; + static const int CXType_OCLImage2dWO = 136; + static const int CXType_OCLImage2dArrayWO = 137; + static const int CXType_OCLImage2dDepthWO = 138; + static const int CXType_OCLImage2dArrayDepthWO = 139; + static const int CXType_OCLImage2dMSAAWO = 140; + static const int CXType_OCLImage2dArrayMSAAWO = 141; + static const int CXType_OCLImage2dMSAADepthWO = 142; + static const int CXType_OCLImage2dArrayMSAADepthWO = 143; + static const int CXType_OCLImage3dWO = 144; + static const int CXType_OCLImage1dRW = 145; + static const int CXType_OCLImage1dArrayRW = 146; + static const int CXType_OCLImage1dBufferRW = 147; + static const int CXType_OCLImage2dRW = 148; + static const int CXType_OCLImage2dArrayRW = 149; + static const int CXType_OCLImage2dDepthRW = 150; + static const int CXType_OCLImage2dArrayDepthRW = 151; + static const int CXType_OCLImage2dMSAARW = 152; + static const int CXType_OCLImage2dArrayMSAARW = 153; + static const int CXType_OCLImage2dMSAADepthRW = 154; + static const int CXType_OCLImage2dArrayMSAADepthRW = 155; + static const int CXType_OCLImage3dRW = 156; + static const int CXType_OCLSampler = 157; + static const int CXType_OCLEvent = 158; + static const int CXType_OCLQueue = 159; + static const int CXType_OCLReserveID = 160; + static const int CXType_ObjCObject = 161; + static const int CXType_ObjCTypeParam = 162; + static const int CXType_Attributed = 163; + static const int CXType_OCLIntelSubgroupAVCMcePayload = 164; + static const int CXType_OCLIntelSubgroupAVCImePayload = 165; + static const int CXType_OCLIntelSubgroupAVCRefPayload = 166; + static const int CXType_OCLIntelSubgroupAVCSicPayload = 167; + static const int CXType_OCLIntelSubgroupAVCMceResult = 168; + static const int CXType_OCLIntelSubgroupAVCImeResult = 169; + static const int CXType_OCLIntelSubgroupAVCRefResult = 170; + static const int CXType_OCLIntelSubgroupAVCSicResult = 171; + static const int CXType_OCLIntelSubgroupAVCImeResultSingleRefStreamout = 172; + static const int CXType_OCLIntelSubgroupAVCImeResultDualRefStreamout = 173; + static const int CXType_OCLIntelSubgroupAVCImeSingleRefStreamin = 174; + static const int CXType_OCLIntelSubgroupAVCImeDualRefStreamin = 175; + static const int CXType_ExtVector = 176; +} + +/// Provides the contents of a file that has not yet been saved to disk. +class CXUnsavedFile extends ffi.Struct { + ffi.Pointer Filename; + + ffi.Pointer Contents; + + @ffi.Uint64() + int Length; +} + +typedef ModifiedCXCursorVisitor = ffi.Int32 Function( + ffi.Pointer, + ffi.Pointer, + ffi.Pointer, +); + +ffi.Pointer clang_Cursor_getArgument_wrap( + ffi.Pointer cursor, + int i, +) { + return _clang_Cursor_getArgument_wrap( + cursor, + i, + ); +} + +final _dart_clang_Cursor_getArgument_wrap _clang_Cursor_getArgument_wrap = + _dylib.lookupFunction<_c_clang_Cursor_getArgument_wrap, + _dart_clang_Cursor_getArgument_wrap>('clang_Cursor_getArgument_wrap'); + +typedef _c_clang_Cursor_getArgument_wrap = ffi.Pointer Function( + ffi.Pointer cursor, + ffi.Uint32 i, +); + +typedef _dart_clang_Cursor_getArgument_wrap = ffi.Pointer Function( + ffi.Pointer cursor, + int i, +); + +/// Returns the first paragraph of doxygen doc comment. +ffi.Pointer clang_Cursor_getBriefCommentText_wrap( + ffi.Pointer cursor, +) { + return _clang_Cursor_getBriefCommentText_wrap( + cursor, + ); +} + +final _dart_clang_Cursor_getBriefCommentText_wrap + _clang_Cursor_getBriefCommentText_wrap = _dylib.lookupFunction< + _c_clang_Cursor_getBriefCommentText_wrap, + _dart_clang_Cursor_getBriefCommentText_wrap>( + 'clang_Cursor_getBriefCommentText_wrap'); + +typedef _c_clang_Cursor_getBriefCommentText_wrap = ffi.Pointer + Function( + ffi.Pointer cursor, +); + +typedef _dart_clang_Cursor_getBriefCommentText_wrap = ffi.Pointer + Function( + ffi.Pointer cursor, +); + +int clang_Cursor_getNumArguments_wrap( + ffi.Pointer cursor, +) { + return _clang_Cursor_getNumArguments_wrap( + cursor, + ); +} + +final _dart_clang_Cursor_getNumArguments_wrap + _clang_Cursor_getNumArguments_wrap = _dylib.lookupFunction< + _c_clang_Cursor_getNumArguments_wrap, + _dart_clang_Cursor_getNumArguments_wrap>( + 'clang_Cursor_getNumArguments_wrap'); + +typedef _c_clang_Cursor_getNumArguments_wrap = ffi.Int32 Function( + ffi.Pointer cursor, +); + +typedef _dart_clang_Cursor_getNumArguments_wrap = int Function( + ffi.Pointer cursor, +); + +ffi.Pointer clang_Type_getNamedType_wrap( + ffi.Pointer elaboratedType, +) { + return _clang_Type_getNamedType_wrap( + elaboratedType, + ); +} + +final _dart_clang_Type_getNamedType_wrap _clang_Type_getNamedType_wrap = + _dylib.lookupFunction<_c_clang_Type_getNamedType_wrap, + _dart_clang_Type_getNamedType_wrap>('clang_Type_getNamedType_wrap'); + +typedef _c_clang_Type_getNamedType_wrap = ffi.Pointer Function( + ffi.Pointer elaboratedType, +); + +typedef _dart_clang_Type_getNamedType_wrap = ffi.Pointer Function( + ffi.Pointer elaboratedType, +); + +/// Provides a shared context for creating translation units. +ffi.Pointer clang_createIndex( + int excludeDeclarationsFromPCH, + int displayDiagnostics, +) { + return _clang_createIndex( + excludeDeclarationsFromPCH, + displayDiagnostics, + ); +} + +final _dart_clang_createIndex _clang_createIndex = + _dylib.lookupFunction<_c_clang_createIndex, _dart_clang_createIndex>( + 'clang_createIndex'); + +typedef _c_clang_createIndex = ffi.Pointer Function( + ffi.Int32 excludeDeclarationsFromPCH, + ffi.Int32 displayDiagnostics, +); + +typedef _dart_clang_createIndex = ffi.Pointer Function( + int excludeDeclarationsFromPCH, + int displayDiagnostics, +); + +/// Destroy a diagnostic. +void clang_disposeDiagnostic( + ffi.Pointer Diagnostic, +) { + return _clang_disposeDiagnostic( + Diagnostic, + ); +} + +final _dart_clang_disposeDiagnostic _clang_disposeDiagnostic = _dylib + .lookupFunction<_c_clang_disposeDiagnostic, _dart_clang_disposeDiagnostic>( + 'clang_disposeDiagnostic'); + +typedef _c_clang_disposeDiagnostic = ffi.Void Function( + ffi.Pointer Diagnostic, +); + +typedef _dart_clang_disposeDiagnostic = void Function( + ffi.Pointer Diagnostic, +); + +/// Destroy the given index. +void clang_disposeIndex( + ffi.Pointer index, +) { + return _clang_disposeIndex( + index, + ); +} + +final _dart_clang_disposeIndex _clang_disposeIndex = + _dylib.lookupFunction<_c_clang_disposeIndex, _dart_clang_disposeIndex>( + 'clang_disposeIndex'); + +typedef _c_clang_disposeIndex = ffi.Void Function( + ffi.Pointer index, +); + +typedef _dart_clang_disposeIndex = void Function( + ffi.Pointer index, +); + +void clang_disposeString_wrap( + ffi.Pointer string, +) { + return _clang_disposeString_wrap( + string, + ); +} + +final _dart_clang_disposeString_wrap _clang_disposeString_wrap = + _dylib.lookupFunction<_c_clang_disposeString_wrap, + _dart_clang_disposeString_wrap>('clang_disposeString_wrap'); + +typedef _c_clang_disposeString_wrap = ffi.Void Function( + ffi.Pointer string, +); + +typedef _dart_clang_disposeString_wrap = void Function( + ffi.Pointer string, +); + +/// Destroy the specified CXTranslationUnit object. +void clang_disposeTranslationUnit( + ffi.Pointer arg0, +) { + return _clang_disposeTranslationUnit( + arg0, + ); +} + +final _dart_clang_disposeTranslationUnit _clang_disposeTranslationUnit = + _dylib.lookupFunction<_c_clang_disposeTranslationUnit, + _dart_clang_disposeTranslationUnit>('clang_disposeTranslationUnit'); + +typedef _c_clang_disposeTranslationUnit = ffi.Void Function( + ffi.Pointer arg0, +); + +typedef _dart_clang_disposeTranslationUnit = void Function( + ffi.Pointer arg0, +); + +ffi.Pointer clang_formatDiagnostic_wrap( + ffi.Pointer diag, + int opts, +) { + return _clang_formatDiagnostic_wrap( + diag, + opts, + ); +} + +final _dart_clang_formatDiagnostic_wrap _clang_formatDiagnostic_wrap = + _dylib.lookupFunction<_c_clang_formatDiagnostic_wrap, + _dart_clang_formatDiagnostic_wrap>('clang_formatDiagnostic_wrap'); + +typedef _c_clang_formatDiagnostic_wrap = ffi.Pointer Function( + ffi.Pointer diag, + ffi.Int32 opts, +); + +typedef _dart_clang_formatDiagnostic_wrap = ffi.Pointer Function( + ffi.Pointer diag, + int opts, +); + +ffi.Pointer clang_getArgType_wrap( + ffi.Pointer cxtype, + int i, +) { + return _clang_getArgType_wrap( + cxtype, + i, + ); +} + +final _dart_clang_getArgType_wrap _clang_getArgType_wrap = _dylib + .lookupFunction<_c_clang_getArgType_wrap, _dart_clang_getArgType_wrap>( + 'clang_getArgType_wrap'); + +typedef _c_clang_getArgType_wrap = ffi.Pointer Function( + ffi.Pointer cxtype, + ffi.Uint32 i, +); + +typedef _dart_clang_getArgType_wrap = ffi.Pointer Function( + ffi.Pointer cxtype, + int i, +); + +ffi.Pointer clang_getArrayElementType_wrap( + ffi.Pointer cxtype, +) { + return _clang_getArrayElementType_wrap( + cxtype, + ); +} + +final _dart_clang_getArrayElementType_wrap _clang_getArrayElementType_wrap = + _dylib.lookupFunction<_c_clang_getArrayElementType_wrap, + _dart_clang_getArrayElementType_wrap>('clang_getArrayElementType_wrap'); + +typedef _c_clang_getArrayElementType_wrap = ffi.Pointer Function( + ffi.Pointer cxtype, +); + +typedef _dart_clang_getArrayElementType_wrap = ffi.Pointer Function( + ffi.Pointer cxtype, +); + +ffi.Pointer clang_getCString_wrap( + ffi.Pointer string, +) { + return _clang_getCString_wrap( + string, + ); +} + +final _dart_clang_getCString_wrap _clang_getCString_wrap = _dylib + .lookupFunction<_c_clang_getCString_wrap, _dart_clang_getCString_wrap>( + 'clang_getCString_wrap'); + +typedef _c_clang_getCString_wrap = ffi.Pointer Function( + ffi.Pointer string, +); + +typedef _dart_clang_getCString_wrap = ffi.Pointer Function( + ffi.Pointer string, +); + +ffi.Pointer clang_getCanonicalType_wrap( + ffi.Pointer typerefType, +) { + return _clang_getCanonicalType_wrap( + typerefType, + ); +} + +final _dart_clang_getCanonicalType_wrap _clang_getCanonicalType_wrap = + _dylib.lookupFunction<_c_clang_getCanonicalType_wrap, + _dart_clang_getCanonicalType_wrap>('clang_getCanonicalType_wrap'); + +typedef _c_clang_getCanonicalType_wrap = ffi.Pointer Function( + ffi.Pointer typerefType, +); + +typedef _dart_clang_getCanonicalType_wrap = ffi.Pointer Function( + ffi.Pointer typerefType, +); + +ffi.Pointer clang_getCursorKindSpelling_wrap( + int kind, +) { + return _clang_getCursorKindSpelling_wrap( + kind, + ); +} + +final _dart_clang_getCursorKindSpelling_wrap _clang_getCursorKindSpelling_wrap = + _dylib.lookupFunction<_c_clang_getCursorKindSpelling_wrap, + _dart_clang_getCursorKindSpelling_wrap>( + 'clang_getCursorKindSpelling_wrap'); + +typedef _c_clang_getCursorKindSpelling_wrap = ffi.Pointer Function( + ffi.Int32 kind, +); + +typedef _dart_clang_getCursorKindSpelling_wrap = ffi.Pointer Function( + int kind, +); + +int clang_getCursorKind_wrap( + ffi.Pointer cursor, +) { + return _clang_getCursorKind_wrap( + cursor, + ); +} + +final _dart_clang_getCursorKind_wrap _clang_getCursorKind_wrap = + _dylib.lookupFunction<_c_clang_getCursorKind_wrap, + _dart_clang_getCursorKind_wrap>('clang_getCursorKind_wrap'); + +typedef _c_clang_getCursorKind_wrap = ffi.Int32 Function( + ffi.Pointer cursor, +); + +typedef _dart_clang_getCursorKind_wrap = int Function( + ffi.Pointer cursor, +); + +ffi.Pointer clang_getCursorLocation_wrap( + ffi.Pointer cursor, +) { + return _clang_getCursorLocation_wrap( + cursor, + ); +} + +final _dart_clang_getCursorLocation_wrap _clang_getCursorLocation_wrap = + _dylib.lookupFunction<_c_clang_getCursorLocation_wrap, + _dart_clang_getCursorLocation_wrap>('clang_getCursorLocation_wrap'); + +typedef _c_clang_getCursorLocation_wrap = ffi.Pointer + Function( + ffi.Pointer cursor, +); + +typedef _dart_clang_getCursorLocation_wrap = ffi.Pointer + Function( + ffi.Pointer cursor, +); + +/// The name of parameter, struct, typedef. +ffi.Pointer clang_getCursorSpelling_wrap( + ffi.Pointer cursor, +) { + return _clang_getCursorSpelling_wrap( + cursor, + ); +} + +final _dart_clang_getCursorSpelling_wrap _clang_getCursorSpelling_wrap = + _dylib.lookupFunction<_c_clang_getCursorSpelling_wrap, + _dart_clang_getCursorSpelling_wrap>('clang_getCursorSpelling_wrap'); + +typedef _c_clang_getCursorSpelling_wrap = ffi.Pointer Function( + ffi.Pointer cursor, +); + +typedef _dart_clang_getCursorSpelling_wrap = ffi.Pointer Function( + ffi.Pointer cursor, +); + +ffi.Pointer clang_getCursorType_wrap( + ffi.Pointer cursor, +) { + return _clang_getCursorType_wrap( + cursor, + ); +} + +final _dart_clang_getCursorType_wrap _clang_getCursorType_wrap = + _dylib.lookupFunction<_c_clang_getCursorType_wrap, + _dart_clang_getCursorType_wrap>('clang_getCursorType_wrap'); + +typedef _c_clang_getCursorType_wrap = ffi.Pointer Function( + ffi.Pointer cursor, +); + +typedef _dart_clang_getCursorType_wrap = ffi.Pointer Function( + ffi.Pointer cursor, +); + +/// Retrieve a diagnostic associated with the given translation unit. +ffi.Pointer clang_getDiagnostic( + ffi.Pointer Unit, + int Index, +) { + return _clang_getDiagnostic( + Unit, + Index, + ); +} + +final _dart_clang_getDiagnostic _clang_getDiagnostic = + _dylib.lookupFunction<_c_clang_getDiagnostic, _dart_clang_getDiagnostic>( + 'clang_getDiagnostic'); + +typedef _c_clang_getDiagnostic = ffi.Pointer Function( + ffi.Pointer Unit, + ffi.Uint32 Index, +); + +typedef _dart_clang_getDiagnostic = ffi.Pointer Function( + ffi.Pointer Unit, + int Index, +); + +int clang_getEnumConstantDeclValue_wrap( + ffi.Pointer cursor, +) { + return _clang_getEnumConstantDeclValue_wrap( + cursor, + ); +} + +final _dart_clang_getEnumConstantDeclValue_wrap + _clang_getEnumConstantDeclValue_wrap = _dylib.lookupFunction< + _c_clang_getEnumConstantDeclValue_wrap, + _dart_clang_getEnumConstantDeclValue_wrap>( + 'clang_getEnumConstantDeclValue_wrap'); + +typedef _c_clang_getEnumConstantDeclValue_wrap = ffi.Int64 Function( + ffi.Pointer cursor, +); + +typedef _dart_clang_getEnumConstantDeclValue_wrap = int Function( + ffi.Pointer cursor, +); + +void clang_getFileLocation_wrap( + ffi.Pointer location, + ffi.Pointer> file, + ffi.Pointer line, + ffi.Pointer column, + ffi.Pointer offset, +) { + return _clang_getFileLocation_wrap( + location, + file, + line, + column, + offset, + ); +} + +final _dart_clang_getFileLocation_wrap _clang_getFileLocation_wrap = + _dylib.lookupFunction<_c_clang_getFileLocation_wrap, + _dart_clang_getFileLocation_wrap>('clang_getFileLocation_wrap'); + +typedef _c_clang_getFileLocation_wrap = ffi.Void Function( + ffi.Pointer location, + ffi.Pointer> file, + ffi.Pointer line, + ffi.Pointer column, + ffi.Pointer offset, +); + +typedef _dart_clang_getFileLocation_wrap = void Function( + ffi.Pointer location, + ffi.Pointer> file, + ffi.Pointer line, + ffi.Pointer column, + ffi.Pointer offset, +); + +ffi.Pointer clang_getFileName_wrap( + ffi.Pointer SFile, +) { + return _clang_getFileName_wrap( + SFile, + ); +} + +final _dart_clang_getFileName_wrap _clang_getFileName_wrap = _dylib + .lookupFunction<_c_clang_getFileName_wrap, _dart_clang_getFileName_wrap>( + 'clang_getFileName_wrap'); + +typedef _c_clang_getFileName_wrap = ffi.Pointer Function( + ffi.Pointer SFile, +); + +typedef _dart_clang_getFileName_wrap = ffi.Pointer Function( + ffi.Pointer SFile, +); + +int clang_getNumArgTypes_wrap( + ffi.Pointer cxtype, +) { + return _clang_getNumArgTypes_wrap( + cxtype, + ); +} + +final _dart_clang_getNumArgTypes_wrap _clang_getNumArgTypes_wrap = + _dylib.lookupFunction<_c_clang_getNumArgTypes_wrap, + _dart_clang_getNumArgTypes_wrap>('clang_getNumArgTypes_wrap'); + +typedef _c_clang_getNumArgTypes_wrap = ffi.Int32 Function( + ffi.Pointer cxtype, +); + +typedef _dart_clang_getNumArgTypes_wrap = int Function( + ffi.Pointer cxtype, +); + +/// Determine the number of diagnostics produced for the given translation unit. +int clang_getNumDiagnostics( + ffi.Pointer Unit, +) { + return _clang_getNumDiagnostics( + Unit, + ); +} + +final _dart_clang_getNumDiagnostics _clang_getNumDiagnostics = _dylib + .lookupFunction<_c_clang_getNumDiagnostics, _dart_clang_getNumDiagnostics>( + 'clang_getNumDiagnostics'); + +typedef _c_clang_getNumDiagnostics = ffi.Uint32 Function( + ffi.Pointer Unit, +); + +typedef _dart_clang_getNumDiagnostics = int Function( + ffi.Pointer Unit, +); + +int clang_getNumElements_wrap( + ffi.Pointer cxtype, +) { + return _clang_getNumElements_wrap( + cxtype, + ); +} + +final _dart_clang_getNumElements_wrap _clang_getNumElements_wrap = + _dylib.lookupFunction<_c_clang_getNumElements_wrap, + _dart_clang_getNumElements_wrap>('clang_getNumElements_wrap'); + +typedef _c_clang_getNumElements_wrap = ffi.Uint64 Function( + ffi.Pointer cxtype, +); + +typedef _dart_clang_getNumElements_wrap = int Function( + ffi.Pointer cxtype, +); + +ffi.Pointer clang_getPointeeType_wrap( + ffi.Pointer pointerType, +) { + return _clang_getPointeeType_wrap( + pointerType, + ); +} + +final _dart_clang_getPointeeType_wrap _clang_getPointeeType_wrap = + _dylib.lookupFunction<_c_clang_getPointeeType_wrap, + _dart_clang_getPointeeType_wrap>('clang_getPointeeType_wrap'); + +typedef _c_clang_getPointeeType_wrap = ffi.Pointer Function( + ffi.Pointer pointerType, +); + +typedef _dart_clang_getPointeeType_wrap = ffi.Pointer Function( + ffi.Pointer pointerType, +); + +ffi.Pointer clang_getResultType_wrap( + ffi.Pointer functionType, +) { + return _clang_getResultType_wrap( + functionType, + ); +} + +final _dart_clang_getResultType_wrap _clang_getResultType_wrap = + _dylib.lookupFunction<_c_clang_getResultType_wrap, + _dart_clang_getResultType_wrap>('clang_getResultType_wrap'); + +typedef _c_clang_getResultType_wrap = ffi.Pointer Function( + ffi.Pointer functionType, +); + +typedef _dart_clang_getResultType_wrap = ffi.Pointer Function( + ffi.Pointer functionType, +); + +ffi.Pointer clang_getTranslationUnitCursor_wrap( + ffi.Pointer tu, +) { + return _clang_getTranslationUnitCursor_wrap( + tu, + ); +} + +final _dart_clang_getTranslationUnitCursor_wrap + _clang_getTranslationUnitCursor_wrap = _dylib.lookupFunction< + _c_clang_getTranslationUnitCursor_wrap, + _dart_clang_getTranslationUnitCursor_wrap>( + 'clang_getTranslationUnitCursor_wrap'); + +typedef _c_clang_getTranslationUnitCursor_wrap = ffi.Pointer Function( + ffi.Pointer tu, +); + +typedef _dart_clang_getTranslationUnitCursor_wrap = ffi.Pointer + Function( + ffi.Pointer tu, +); + +ffi.Pointer clang_getTypeDeclaration_wrap( + ffi.Pointer cxtype, +) { + return _clang_getTypeDeclaration_wrap( + cxtype, + ); +} + +final _dart_clang_getTypeDeclaration_wrap _clang_getTypeDeclaration_wrap = + _dylib.lookupFunction<_c_clang_getTypeDeclaration_wrap, + _dart_clang_getTypeDeclaration_wrap>('clang_getTypeDeclaration_wrap'); + +typedef _c_clang_getTypeDeclaration_wrap = ffi.Pointer Function( + ffi.Pointer cxtype, +); + +typedef _dart_clang_getTypeDeclaration_wrap = ffi.Pointer Function( + ffi.Pointer cxtype, +); + +ffi.Pointer clang_getTypeKindSpelling_wrap( + int typeKind, +) { + return _clang_getTypeKindSpelling_wrap( + typeKind, + ); +} + +final _dart_clang_getTypeKindSpelling_wrap _clang_getTypeKindSpelling_wrap = + _dylib.lookupFunction<_c_clang_getTypeKindSpelling_wrap, + _dart_clang_getTypeKindSpelling_wrap>('clang_getTypeKindSpelling_wrap'); + +typedef _c_clang_getTypeKindSpelling_wrap = ffi.Pointer Function( + ffi.Int32 typeKind, +); + +typedef _dart_clang_getTypeKindSpelling_wrap = ffi.Pointer Function( + int typeKind, +); + +ffi.Pointer clang_getTypeSpelling_wrap( + ffi.Pointer type, +) { + return _clang_getTypeSpelling_wrap( + type, + ); +} + +final _dart_clang_getTypeSpelling_wrap _clang_getTypeSpelling_wrap = + _dylib.lookupFunction<_c_clang_getTypeSpelling_wrap, + _dart_clang_getTypeSpelling_wrap>('clang_getTypeSpelling_wrap'); + +typedef _c_clang_getTypeSpelling_wrap = ffi.Pointer Function( + ffi.Pointer type, +); + +typedef _dart_clang_getTypeSpelling_wrap = ffi.Pointer Function( + ffi.Pointer type, +); + +ffi.Pointer clang_getTypedefDeclUnderlyingType_wrap( + ffi.Pointer cxcursor, +) { + return _clang_getTypedefDeclUnderlyingType_wrap( + cxcursor, + ); +} + +final _dart_clang_getTypedefDeclUnderlyingType_wrap + _clang_getTypedefDeclUnderlyingType_wrap = _dylib.lookupFunction< + _c_clang_getTypedefDeclUnderlyingType_wrap, + _dart_clang_getTypedefDeclUnderlyingType_wrap>( + 'clang_getTypedefDeclUnderlyingType_wrap'); + +typedef _c_clang_getTypedefDeclUnderlyingType_wrap = ffi.Pointer + Function( + ffi.Pointer cxcursor, +); + +typedef _dart_clang_getTypedefDeclUnderlyingType_wrap = ffi.Pointer + Function( + ffi.Pointer cxcursor, +); + +/// Same as clang_parseTranslationUnit2, but returns the CXTranslationUnit instead of an error code. In case of an error this routine returns a NULL CXTranslationUnit, without further detailed error codes. +ffi.Pointer clang_parseTranslationUnit( + ffi.Pointer CIdx, + ffi.Pointer source_filename, + ffi.Pointer> command_line_args, + int num_command_line_args, + ffi.Pointer unsaved_files, + int num_unsaved_files, + int options, +) { + return _clang_parseTranslationUnit( + CIdx, + source_filename, + command_line_args, + num_command_line_args, + unsaved_files, + num_unsaved_files, + options, + ); +} + +final _dart_clang_parseTranslationUnit _clang_parseTranslationUnit = + _dylib.lookupFunction<_c_clang_parseTranslationUnit, + _dart_clang_parseTranslationUnit>('clang_parseTranslationUnit'); + +typedef _c_clang_parseTranslationUnit = ffi.Pointer + Function( + ffi.Pointer CIdx, + ffi.Pointer source_filename, + ffi.Pointer> command_line_args, + ffi.Int32 num_command_line_args, + ffi.Pointer unsaved_files, + ffi.Uint32 num_unsaved_files, + ffi.Uint32 options, +); + +typedef _dart_clang_parseTranslationUnit = ffi.Pointer + Function( + ffi.Pointer CIdx, + ffi.Pointer source_filename, + ffi.Pointer> command_line_args, + int num_command_line_args, + ffi.Pointer unsaved_files, + int num_unsaved_files, + int options, +); + +/// Visitor is a function pointer with parameters having pointers to cxcursor instead of cxcursor by default. +int clang_visitChildren_wrap( + ffi.Pointer parent, + ffi.Pointer> _modifiedVisitor, + ffi.Pointer clientData, +) { + return _clang_visitChildren_wrap( + parent, + _modifiedVisitor, + clientData, + ); +} + +final _dart_clang_visitChildren_wrap _clang_visitChildren_wrap = + _dylib.lookupFunction<_c_clang_visitChildren_wrap, + _dart_clang_visitChildren_wrap>('clang_visitChildren_wrap'); + +typedef _c_clang_visitChildren_wrap = ffi.Uint32 Function( + ffi.Pointer parent, + ffi.Pointer> _modifiedVisitor, + ffi.Pointer clientData, +); + +typedef _dart_clang_visitChildren_wrap = int Function( + ffi.Pointer parent, + ffi.Pointer> _modifiedVisitor, + ffi.Pointer clientData, +); diff --git a/lib/src/header_parser/data.dart b/lib/src/header_parser/data.dart new file mode 100644 index 00000000..900c0ff5 --- /dev/null +++ b/lib/src/header_parser/data.dart @@ -0,0 +1,9 @@ +// Copyright (c) 2020, the Dart project authors. Please see the AUTHORS file +// for details. All rights reserved. Use of this source code is governed by a +// BSD-style license that can be found in the LICENSE file. + +import 'package:ffigen/src/config_provider.dart'; +/// Holds all Global shared variables. + +/// Holds configurations. +Config config; diff --git a/lib/src/header_parser/includer.dart b/lib/src/header_parser/includer.dart new file mode 100644 index 00000000..23698a5f --- /dev/null +++ b/lib/src/header_parser/includer.dart @@ -0,0 +1,95 @@ +// Copyright (c) 2020, the Dart project authors. Please see the AUTHORS file +// for details. All rights reserved. Use of this source code is governed by a +// BSD-style license that can be found in the LICENSE file. + +import 'package:meta/meta.dart'; +import 'package:path/path.dart' as p; +import 'data.dart'; + +/// Utility functions to check whether a binding should be parsed or not +/// based on filters and if a binding is seen already. + +// Stores binding names already scene. +Set _structs = {}; +Set _functions = {}; +Set _enumClass = {}; +Set _typedefC = {}; + +bool shouldIncludeStruct(String name) { + if (_structs.contains(name) || name == '') { + return false; + } else if (config.structFilters == null || + config.structFilters.shouldInclude(name)) { + _structs.add(name); + return true; + } else { + return false; + } +} + +bool shouldIncludeFunc(String name) { + if (_functions.contains(name) || name == '') { + return false; + } else if (config.functionFilters == null || + config.functionFilters.shouldInclude(name)) { + _functions.add(name); + return true; + } else { + return false; + } +} + +bool shouldIncludeEnumClass(String name) { + if (_enumClass.contains(name) || name == '') { + return false; + } else if (config.enumClassFilters == null || + config.enumClassFilters.shouldInclude(name)) { + _enumClass.add(name); + return true; + } else { + return false; + } +} + +/// True if a cursor should be included based on header-filter, use for root +/// declarations. +bool shouldIncludeRootCursor(String sourceFile) { + final name = p.basename(sourceFile); + + if (config.headerFilter.excludedInclusionHeaders.contains(name)) { + return false; + } + + if (config.headerFilter.includedInclusionHeaders.contains(name)) { + return true; + } + + // If any includedInclusionHeaders is provided, return false. + if (config.headerFilter.includedInclusionHeaders.isNotEmpty) { + return false; + } else { + return true; + } +} + +bool isUnseenTypedefC(String name, {@required bool addToSeen}) { + if (_typedefC.contains(name)) { + return false; + } else { + if (addToSeen) { + _typedefC.add(name); + } + return true; + } +} + +bool isUnseenStruct(String name, {@required bool addToSeen}) { + if (_structs.contains(name)) { + return false; + } else { + if (addToSeen) { + _structs.add(name); + } + return true; + } +} diff --git a/lib/src/header_parser/parser.dart b/lib/src/header_parser/parser.dart new file mode 100644 index 00000000..eac3c93c --- /dev/null +++ b/lib/src/header_parser/parser.dart @@ -0,0 +1,96 @@ +// Copyright (c) 2020, the Dart project authors. Please see the AUTHORS file +// for details. All rights reserved. Use of this source code is governed by a +// BSD-style license that can be found in the LICENSE file. + +import 'dart:ffi'; + +import 'package:ffi/ffi.dart'; +import 'package:ffigen/src/code_generator.dart'; +import 'package:ffigen/src/config_provider.dart'; +import 'package:ffigen/src/header_parser/translation_unit_parser.dart'; +import 'package:logging/logging.dart'; + +import 'clang_bindings/clang_bindings.dart' as clang; +import 'data.dart' as data; +import 'utils.dart'; + +/// Main entrypoint for header_parser. +Library parse(Config conf, {bool sort = false}) { + initParser(conf); + + final bindings = parseToBindings(); + + final library = Library(bindings: bindings); + + if (sort) { + library.sort(); + } + return library; +} + +// =================================================================================== +// BELOW FUNCTIONS ARE MEANT FOR INTERNAL USE AND TESTING +// =================================================================================== + +var _logger = Logger('parser:parser'); + +/// initialises parser, clears any previous values. +void initParser(Config c) { + data.config = c; + + clang.init(DynamicLibrary.open(data.config.libclang_dylib_path)); +} + +/// Parses source files and adds generated bindings to [bindings]. +List parseToBindings() { + final index = clang.clang_createIndex(0, 0); + + Pointer> clangCmdArgs = nullptr; + var cmdLen = 0; + if (data.config.compilerOpts != null) { + clangCmdArgs = createDynamicStringArray(data.config.compilerOpts); + cmdLen = data.config.compilerOpts.length; + } + + // Contains all bindings. + final bindings = []; + + // Log all headers for user. + _logger.info('Input Headers: ${data.config.headers}'); + + for (final headerLocation in data.config.headers) { + _logger.fine('Creating TranslationUnit for header: $headerLocation'); + + final tu = clang.clang_parseTranslationUnit( + index, + Utf8.toUtf8(headerLocation).cast(), + clangCmdArgs.cast(), + cmdLen, + nullptr, + 0, + clang.CXTranslationUnit_Flags.CXTranslationUnit_SkipFunctionBodies, + ); + + if (tu == nullptr) { + _logger.severe( + "Skipped header/file: $headerLocation, couldn't parse source."); + // Skip parsing this header. + continue; + } + + logTuDiagnostics(tu, _logger, headerLocation); + final rootCursor = clang.clang_getTranslationUnitCursor_wrap(tu); + + bindings.addAll(parseTranslationUnit(rootCursor)); + + // Cleanup. + rootCursor.dispose(); + clang.clang_disposeTranslationUnit(tu); + } + + if (data.config.compilerOpts != null) { + clangCmdArgs.dispose(data.config.compilerOpts.length); + } + clang.clang_disposeIndex(index); + return bindings; +} diff --git a/lib/src/header_parser/sub_parsers/enumdecl_parser.dart b/lib/src/header_parser/sub_parsers/enumdecl_parser.dart new file mode 100644 index 00000000..19fd1ced --- /dev/null +++ b/lib/src/header_parser/sub_parsers/enumdecl_parser.dart @@ -0,0 +1,88 @@ +// Copyright (c) 2020, the Dart project authors. Please see the AUTHORS file +// for details. All rights reserved. Use of this source code is governed by a +// BSD-style license that can be found in the LICENSE file. + +import 'dart:ffi'; + +import 'package:ffigen/src/code_generator.dart'; +import 'package:logging/logging.dart'; + +import '../clang_bindings/clang_bindings.dart' as clang; +import '../includer.dart'; +import '../utils.dart'; + +var _logger = Logger('parser:enumdecl_parser'); + +/// Temporarily holds a enumClass before its returned by [parseEnumDeclaration]. +EnumClass _enumClass; + +/// Parses a function declaration. +EnumClass parseEnumDeclaration( + Pointer cursor, { + + /// Optionally provide name to use (useful in case struct is inside a typedef). + String name, +}) { + _enumClass = null; + + final enumName = name ?? cursor.spelling(); + if (enumName == '') { + _logger.finest('unnamed enum declaration'); + } else if (shouldIncludeEnumClass(enumName)) { + _logger.fine('++++ Adding Enum: ${cursor.completeStringRepr()}'); + _enumClass = EnumClass( + dartDoc: getCursorDocComment(cursor), + name: enumName, + ); + _addEnumConstant(cursor); + } + + return _enumClass; +} + +void _addEnumConstant(Pointer cursor) { + final resultCode = clang.clang_visitChildren_wrap( + cursor, + Pointer.fromFunction( + _enumCursorVisitor, clang.CXChildVisitResult.CXChildVisit_Break), + nullptr, + ); + + visitChildrenResultChecker(resultCode); +} + +/// Visitor for a enum cursor [clang.CXCursorKind.CXCursor_EnumDecl]. +/// +/// Invoked on every enum directly under rootCursor. +/// Used for for extracting enum values. +int _enumCursorVisitor(Pointer cursor, + Pointer parent, Pointer clientData) { + try { + _logger.finest(' enumCursorVisitor: ${cursor.completeStringRepr()}'); + switch (clang.clang_getCursorKind_wrap(cursor)) { + case clang.CXCursorKind.CXCursor_EnumConstantDecl: + _addEnumConstantToEnumClass(cursor); + break; + default: + print('invalid enum constant'); + } + cursor.dispose(); + parent.dispose(); + } catch (e, s) { + _logger.severe(e); + _logger.severe(s); + rethrow; + } + return clang.CXChildVisitResult.CXChildVisit_Continue; +} + +/// Adds the parameter to func in [functiondecl_parser.dart]. +void _addEnumConstantToEnumClass(Pointer cursor) { + _enumClass.enumConstants.add( + EnumConstant( + // Extracting doc comment doesn't always give the right comment + // so we are skipping dartdoc for individual enum constants. + name: cursor.spelling(), + value: clang.clang_getEnumConstantDeclValue_wrap(cursor)), + ); +} diff --git a/lib/src/header_parser/sub_parsers/functiondecl_parser.dart b/lib/src/header_parser/sub_parsers/functiondecl_parser.dart new file mode 100644 index 00000000..62803f64 --- /dev/null +++ b/lib/src/header_parser/sub_parsers/functiondecl_parser.dart @@ -0,0 +1,113 @@ +// Copyright (c) 2020, the Dart project authors. Please see the AUTHORS file +// for details. All rights reserved. Use of this source code is governed by a +// BSD-style license that can be found in the LICENSE file. + +import 'dart:ffi'; + +import 'package:ffigen/src/code_generator.dart'; +import 'package:logging/logging.dart'; + +import '../clang_bindings/clang_bindings.dart' as clang; +import '../includer.dart'; +import '../utils.dart'; + +var _logger = Logger('parser:functiondecl_parser'); + +/// Temporarily holds a function before its returned by [parseFunctionDeclaration]. +Func _func; + +/// Parses a function declaration. +Func parseFunctionDeclaration(Pointer cursor) { + _func = null; + structByValueParameter = false; + unimplementedParameterType = false; + constantArrayParameterType = false; + + final name = cursor.spelling(); + if (shouldIncludeFunc(name)) { + _logger.fine('++++ Adding Function: ${cursor.completeStringRepr()}'); + + final rt = _getFunctionReturnType(cursor); + final parameters = _getParameters(cursor); + + //TODO(3): Remove this when support for Structs by value arrives. + if (rt.broadType == BroadType.Struct || structByValueParameter) { + _logger.fine( + '---- Removed Function, reason: struct pass/return by value: ${cursor.completeStringRepr()}'); + _logger.warning( + "Skipped Function '$name', struct pass/return by value not supported."); + return null; // Returning null so that [addToBindings] function excludes this. + } + + if (constantArrayParameterType) { + _logger.fine( + '---- Removed Function, reason: constant array passed to function parameter: ${cursor.completeStringRepr()}'); + _logger.warning( + "Skipped Function '$name', constant array in function parameter not supported."); + return null; // Returning null so that [addToBindings] function excludes this. + } + + if (rt.getBaseBroadType() == BroadType.Unimplemented || + unimplementedParameterType) { + _logger.fine( + '---- Removed Function, reason: unsupported return type or parameter type: ${cursor.completeStringRepr()}'); + _logger.warning( + "Skipped Function '$name', function has unsupported return type or parameter type."); + return null; // Returning null so that [addToBindings] function excludes this. + } + + _func = Func( + dartDoc: getCursorDocComment(cursor), + name: name, + returnType: rt, + parameters: parameters, + ); + } + + return _func; +} + +bool structByValueParameter = false; +bool constantArrayParameterType = false; +bool unimplementedParameterType = false; +Type _getFunctionReturnType(Pointer cursor) { + return cursor.returnType().toCodeGenTypeAndDispose(); +} + +List _getParameters(Pointer cursor) { + final parameters = []; + + final totalArgs = clang.clang_Cursor_getNumArguments_wrap(cursor); + for (var i = 0; i < totalArgs; i++) { + final paramCursor = clang.clang_Cursor_getArgument_wrap(cursor, i); + + _logger.finer('===== parameter: ${paramCursor.completeStringRepr()}'); + + final pt = _getParameterType(paramCursor); + //TODO(3): Remove this when support for Structs by value arrives. + if (pt.broadType == BroadType.Struct) { + structByValueParameter = true; + } else if (pt.broadType == BroadType.ConstantArray) { + constantArrayParameterType = true; + } else if (pt.getBaseBroadType() == BroadType.Unimplemented) { + unimplementedParameterType = true; + } + + final pn = paramCursor.spelling(); + + /// If [pn] is null or empty, its set to `arg$i` by code_generator. + parameters.add( + Parameter( + name: pn, + type: pt, + ), + ); + paramCursor.dispose(); + } + + return parameters; +} + +Type _getParameterType(Pointer cursor) { + return cursor.type().toCodeGenTypeAndDispose(); +} diff --git a/lib/src/header_parser/sub_parsers/structdecl_parser.dart b/lib/src/header_parser/sub_parsers/structdecl_parser.dart new file mode 100644 index 00000000..27d8efdd --- /dev/null +++ b/lib/src/header_parser/sub_parsers/structdecl_parser.dart @@ -0,0 +1,129 @@ +// Copyright (c) 2020, the Dart project authors. Please see the AUTHORS file +// for details. All rights reserved. Use of this source code is governed by a +// BSD-style license that can be found in the LICENSE file. + +import 'dart:ffi'; + +import 'package:ffigen/src/code_generator.dart'; +import 'package:logging/logging.dart'; + +import '../clang_bindings/clang_bindings.dart' as clang; +import '../includer.dart'; +import '../utils.dart'; + +var _logger = Logger('parser:structdecl_parser'); + +/// Temporarily holds a struc before its returned by [parseStructDeclaration]. +Struc _struc; + +/// Parses a struct declaration. +Struc parseStructDeclaration( + Pointer cursor, { + + /// Optionally provide name (useful in case struct is inside a typedef). + String name, + + /// Option to override shouldInclude methods. (Useful in case of extracting + /// structs when they are passed/returned by an included function.) + /// + /// Check if binding is not already included before setting this to true. + bool doInclude = false, +}) { + _struc = null; + final structName = name ?? cursor.spelling(); + + if (structName == '') { + _logger.finest('unnamed structure or typedef structure declaration'); + return null; + } else if (doInclude || shouldIncludeStruct(structName)) { + _logger.fine( + '++++ Adding Structure: structName: ${structName}, ${cursor.completeStringRepr()}'); + + final members = _getMembers(cursor, structName); + _struc = Struc( + dartDoc: getCursorDocComment(cursor), + name: structName, + members: members, + ); + } + + return _struc; +} + +List _members; +List _getMembers(Pointer cursor, String structName) { + _members = []; + nestedStructMember = false; + unimplementedMemberType = false; + + final resultCode = clang.clang_visitChildren_wrap( + cursor, + Pointer.fromFunction( + _structMembersVisitor, clang.CXChildVisitResult.CXChildVisit_Break), + nullptr); + + visitChildrenResultChecker(resultCode); + + // Returning null to exclude the struct members as it has a struct by value field. + if (nestedStructMember) { + _logger.fine( + '---- Removed Struct members, reason: struct has struct members ${cursor.completeStringRepr()}'); + _logger.warning( + "Removed All Struct Members from '$structName', Nested Structures not supported."); + return null; + } else if (unimplementedMemberType) { + _logger.fine( + '---- Removed Struct members, reason: member with unimplementedtype ${cursor.completeStringRepr()}'); + _logger.warning( + "Removed All Struct Members from '$structName', struct member has an unsupported type."); + return null; + } + + return _members; +} + +bool nestedStructMember = false; +bool unimplementedMemberType = false; + +/// Visitor for the struct cursor [CXCursorKind.CXCursor_StructDecl]. +/// +/// Child visitor invoked on struct cursor. +int _structMembersVisitor(Pointer cursor, + Pointer parent, Pointer clientData) { + try { + if (cursor.kind() == clang.CXCursorKind.CXCursor_FieldDecl) { + _logger.finer('===== member: ${cursor.completeStringRepr()}'); + + final mt = cursor.type().toCodeGenTypeAndDispose(); + + //TODO(4): Remove these when support for Structs by value arrives. + if (mt.broadType == BroadType.Struct) { + // Setting this flag will exclude adding members for this struct's bindings. + nestedStructMember = true; + } else if (mt.broadType == BroadType.ConstantArray) { + if (mt.elementType.broadType == BroadType.Struct) { + // Setting this flag will exclude adding members for this struct's bindings. + nestedStructMember = true; + } + } + + if (mt.getBaseBroadType() == BroadType.Unimplemented) { + unimplementedMemberType = true; + } + + _members.add( + Member( + name: cursor.spelling(), + type: mt, + ), + ); + } + cursor.dispose(); + parent.dispose(); + } catch (e, s) { + _logger.severe(e); + _logger.severe(s); + rethrow; + } + return clang.CXChildVisitResult.CXChildVisit_Continue; +} diff --git a/lib/src/header_parser/sub_parsers/typedefdecl_parser.dart b/lib/src/header_parser/sub_parsers/typedefdecl_parser.dart new file mode 100644 index 00000000..c68b5e33 --- /dev/null +++ b/lib/src/header_parser/sub_parsers/typedefdecl_parser.dart @@ -0,0 +1,71 @@ +// Copyright (c) 2020, the Dart project authors. Please see the AUTHORS file +// for details. All rights reserved. Use of this source code is governed by a +// BSD-style license that can be found in the LICENSE file. + +import 'dart:ffi'; + +import 'package:ffigen/src/code_generator.dart'; +import 'package:logging/logging.dart'; + +import '../clang_bindings/clang_bindings.dart' as clang; +import '../sub_parsers/enumdecl_parser.dart'; +import '../sub_parsers/structdecl_parser.dart'; +import '../utils.dart'; + +var _logger = Logger('parser:typedefdecl_parser'); + +/// Temporarily holds a binding before its returned by [parseTypedefDeclaration]. +Binding _binding; + +/// Temporarily holds parent cursor name. +String _typedefName; + +/// Parses a typedef declaration. +Binding parseTypedefDeclaration(Pointer cursor) { + _binding = null; + // Name of typedef. + _typedefName = cursor.spelling(); + + final resultCode = clang.clang_visitChildren_wrap( + cursor, + Pointer.fromFunction(_typedefdeclarationCursorVisitor, + clang.CXChildVisitResult.CXChildVisit_Break), + nullptr, + ); + + visitChildrenResultChecker(resultCode); + + return _binding; +} + +/// Visitor for extracting binding for a TypedefDeclarations of a +/// [clang.CXCursorKind.CXCursor_TypedefDecl]. +/// +/// Visitor invoked on cursor of type declaration returned by +/// [clang.clang_getTypeDeclaration_wrap]. +int _typedefdeclarationCursorVisitor(Pointer cursor, + Pointer parent, Pointer clientData) { + try { + _logger.finest( + 'typedefdeclarationCursorVisitor: ${cursor.completeStringRepr()}'); + + switch (clang.clang_getCursorKind_wrap(cursor)) { + case clang.CXCursorKind.CXCursor_StructDecl: + _binding = parseStructDeclaration(cursor, name: _typedefName); + break; + case clang.CXCursorKind.CXCursor_EnumDecl: + _binding = parseEnumDeclaration(cursor, name: _typedefName); + break; + default: + _logger.finest('typedefdeclarationCursorVisitor: Ignored'); + } + + cursor.dispose(); + parent.dispose(); + } catch (e, s) { + _logger.severe(e); + _logger.severe(s); + rethrow; + } + return clang.CXChildVisitResult.CXChildVisit_Continue; +} diff --git a/lib/src/header_parser/translation_unit_parser.dart b/lib/src/header_parser/translation_unit_parser.dart new file mode 100644 index 00000000..8632b259 --- /dev/null +++ b/lib/src/header_parser/translation_unit_parser.dart @@ -0,0 +1,80 @@ +// Copyright (c) 2020, the Dart project authors. Please see the AUTHORS file +// for details. All rights reserved. Use of this source code is governed by a +// BSD-style license that can be found in the LICENSE file. + +import 'dart:ffi'; + +import 'package:ffigen/src/code_generator.dart'; +import 'package:logging/logging.dart'; + +import 'clang_bindings/clang_bindings.dart' as clang; +import 'includer.dart'; +import 'sub_parsers/enumdecl_parser.dart'; +import 'sub_parsers/functiondecl_parser.dart'; +import 'sub_parsers/structdecl_parser.dart'; +import 'sub_parsers/typedefdecl_parser.dart'; +import 'utils.dart'; + +var _logger = Logger('parser:root_parser'); + +List _bindings; + +/// Parses the translation unit and returns the generated bindings. +List parseTranslationUnit(Pointer translationUnitCursor) { + _bindings = []; + + final resultCode = clang.clang_visitChildren_wrap( + translationUnitCursor, + Pointer.fromFunction( + _rootCursorVisitor, clang.CXChildVisitResult.CXChildVisit_Break), + nullptr, + ); + + visitChildrenResultChecker(resultCode); + + return _bindings; +} + +/// Child visitor invoked on translationUnitCursor [CXCursorKind.CXCursor_TranslationUnit]. +int _rootCursorVisitor(Pointer cursor, + Pointer parent, Pointer clientData) { + try { + if (shouldIncludeRootCursor(cursor.sourceFileName())) { + _logger.finest('rootCursorVisitor: ${cursor.completeStringRepr()}'); + switch (clang.clang_getCursorKind_wrap(cursor)) { + case clang.CXCursorKind.CXCursor_FunctionDecl: + addToBindings(parseFunctionDeclaration(cursor)); + break; + case clang.CXCursorKind.CXCursor_TypedefDecl: + addToBindings(parseTypedefDeclaration(cursor)); + break; + case clang.CXCursorKind.CXCursor_StructDecl: + addToBindings(parseStructDeclaration(cursor)); + break; + case clang.CXCursorKind.CXCursor_EnumDecl: + addToBindings(parseEnumDeclaration(cursor)); + break; + default: + _logger.finer('rootCursorVisitor: CursorKind not implemented'); + } + } else { + _logger.finest( + 'rootCursorVisitor:(excluded in header-filter) ${cursor.completeStringRepr()}'); + } + + cursor.dispose(); + parent.dispose(); + } catch (e, s) { + _logger.severe(e); + _logger.severe(s); + rethrow; + } + return clang.CXChildVisitResult.CXChildVisit_Continue; +} + +/// Adds to binding if not null. +void addToBindings(Binding b) { + if (b != null) { + _bindings.add(b); + } +} diff --git a/lib/src/header_parser/type_extractor/cxtypekindmap.dart b/lib/src/header_parser/type_extractor/cxtypekindmap.dart new file mode 100644 index 00000000..6dd175f4 --- /dev/null +++ b/lib/src/header_parser/type_extractor/cxtypekindmap.dart @@ -0,0 +1,43 @@ +// Copyright (c) 2020, the Dart project authors. Please see the AUTHORS file +// for details. All rights reserved. Use of this source code is governed by a +// BSD-style license that can be found in the LICENSE file. + +import 'package:ffigen/src/header_parser/clang_bindings/clang_bindings.dart' + as clang; +import 'package:ffigen/src/code_generator.dart' show SupportedNativeType; + +/// Utility to convert CXType to [code_generator.Type]. +/// +/// Key: CXTypekindEnum, Value: TypeString for code_generator +var cxTypeKindToSupportedNativeTypes = { + clang.CXTypeKind.CXType_Void: SupportedNativeType.Void, + clang.CXTypeKind.CXType_UChar: SupportedNativeType.Uint8, + clang.CXTypeKind.CXType_UShort: SupportedNativeType.Uint16, + clang.CXTypeKind.CXType_UInt: SupportedNativeType.Uint32, + clang.CXTypeKind.CXType_ULong: SupportedNativeType.Uint64, + clang.CXTypeKind.CXType_ULongLong: SupportedNativeType.Uint64, + clang.CXTypeKind.CXType_SChar: SupportedNativeType.Int8, + clang.CXTypeKind.CXType_Short: SupportedNativeType.Int16, + clang.CXTypeKind.CXType_Int: SupportedNativeType.Int32, + clang.CXTypeKind.CXType_Long: SupportedNativeType.Int64, + clang.CXTypeKind.CXType_LongLong: SupportedNativeType.Int64, + clang.CXTypeKind.CXType_Float: SupportedNativeType.Float, + clang.CXTypeKind.CXType_Double: SupportedNativeType.Double, + clang.CXTypeKind.CXType_Char_S: SupportedNativeType.Int8, + clang.CXTypeKind.CXType_Enum: SupportedNativeType.Int32, +}; + +SupportedNativeType get enumNativeType => + cxTypeKindToSupportedNativeTypes[clang.CXTypeKind.CXType_Enum]; + +var suportedTypedefToSuportedNativeType = { + 'uint8_t': SupportedNativeType.Uint8, + 'uint16_t': SupportedNativeType.Uint16, + 'uint32_t': SupportedNativeType.Uint32, + 'uint64_t': SupportedNativeType.Uint64, + 'int8_t': SupportedNativeType.Int8, + 'int16_t': SupportedNativeType.Int16, + 'int32_t': SupportedNativeType.Int32, + 'int64_t': SupportedNativeType.Int64, + 'intptr_t': SupportedNativeType.IntPtr, +}; diff --git a/lib/src/header_parser/type_extractor/extractor.dart b/lib/src/header_parser/type_extractor/extractor.dart new file mode 100644 index 00000000..db374876 --- /dev/null +++ b/lib/src/header_parser/type_extractor/extractor.dart @@ -0,0 +1,154 @@ +// Copyright (c) 2020, the Dart project authors. Please see the AUTHORS file +// for details. All rights reserved. Use of this source code is governed by a +// BSD-style license that can be found in the LICENSE file. + +/// Extracts code_gen Type from type. +import 'dart:ffi'; + +import 'package:ffigen/src/code_generator.dart'; +import 'package:logging/logging.dart'; + +import '../clang_bindings/clang_bindings.dart' as clang; +import '../data.dart'; +import '../includer.dart'; +import '../sub_parsers/structdecl_parser.dart'; +import '../translation_unit_parser.dart'; +import '../type_extractor/cxtypekindmap.dart'; +import '../utils.dart'; + +var _logger = Logger('parser:extractor'); +const _padding = ' '; + +/// Converts cxtype to a typestring code_generator can accept. +Type getCodeGenType(Pointer cxtype, {String parentName}) { + _logger.fine('${_padding}getCodeGenType ${cxtype.completeStringRepr()}'); + final kind = cxtype.kind(); + + switch (kind) { + case clang.CXTypeKind.CXType_Pointer: + final pt = clang.clang_getPointeeType_wrap(cxtype); + final s = getCodeGenType(pt, parentName: parentName); + pt.dispose(); + return Type.pointer(s); + case clang.CXTypeKind.CXType_Typedef: + // Get name from typedef name if config allows. + if (config.useSupportedTypedefs) { + final spelling = cxtype.spelling(); + if (suportedTypedefToSuportedNativeType.containsKey(spelling)) { + _logger.fine(' Type Mapped from supported typedef'); + return Type.nativeType(suportedTypedefToSuportedNativeType[spelling]); + } + } + + // This is important or we get stuck in infinite recursion. + final ct = clang.clang_getCanonicalType_wrap(cxtype); + + final s = getCodeGenType(ct, parentName: parentName ?? cxtype.spelling()); + ct.dispose(); + return s; + case clang.CXTypeKind.CXType_Elaborated: + final et = clang.clang_Type_getNamedType_wrap(cxtype); + final s = getCodeGenType(et, parentName: parentName); + et.dispose(); + return s; + case clang.CXTypeKind.CXType_Record: + return _extractfromRecord(cxtype); + case clang.CXTypeKind.CXType_Enum: + return Type.nativeType( + enumNativeType, + ); + case clang.CXTypeKind + .CXType_FunctionProto: // Primarily used for function pointers. + return _extractFromFunctionProto(cxtype, parentName); + case clang.CXTypeKind + .CXType_ConstantArray: // Primarily used for constant array in struct members. + return Type.constantArray( + clang.clang_getNumElements_wrap(cxtype), + clang.clang_getArrayElementType_wrap(cxtype).toCodeGenTypeAndDispose(), + ); + default: + if (cxTypeKindToSupportedNativeTypes.containsKey(kind)) { + return Type.nativeType( + cxTypeKindToSupportedNativeTypes[kind], + ); + } else { + _logger.fine( + 'typedeclarationCursorVisitor: getCodeGenType: Type Not Implemented, ${cxtype.completeStringRepr()}'); + return Type.unimplemented( + 'Type: ${cxtype.kindSpelling()} not implemented'); + } + } +} + +Type _extractfromRecord(Pointer cxtype) { + Type type; + + final cursor = clang.clang_getTypeDeclaration_wrap(cxtype); + _logger.fine('${_padding}_extractfromRecord: ${cursor.completeStringRepr()}'); + + switch (clang.clang_getCursorKind_wrap(cursor)) { + case clang.CXCursorKind.CXCursor_StructDecl: + final cxtype = cursor.type(); + var structName = cursor.spelling(); + if (structName == '') { + // Incase of anonymous structs defined inside a typedef. + structName = cxtype.spelling(); + } + + type = Type.struct(structName); + + // Also add a struct binding, if its unseen. + if (isUnseenStruct(structName, addToSeen: true)) { + addToBindings( + parseStructDeclaration(cursor, name: structName, doInclude: true)); + } + + cxtype.dispose(); + break; + default: + _logger.fine( + 'typedeclarationCursorVisitor: _extractfromRecord: Not Implemented, ${cursor.completeStringRepr()}'); + return Type.unimplemented( + 'Type: ${cxtype.kindSpelling()} not implemented'); + } + cursor.dispose(); + return type; +} + +// Used for function pointer arguments. +Type _extractFromFunctionProto( + Pointer cxtype, String parentName) { + var name = parentName; + + // Set a name for typedefc incase it was null or empty. + if (name == null || name == '') { + name = _getNextUniqueString('_typedefC_noname'); + } + + if (isUnseenTypedefC(name, addToSeen: true)) { + final typedefC = TypedefC( + name: name, + returnType: + clang.clang_getResultType_wrap(cxtype).toCodeGenTypeAndDispose(), + ); + final totalArgs = clang.clang_getNumArgTypes_wrap(cxtype); + for (var i = 0; i < totalArgs; i++) { + final t = clang.clang_getArgType_wrap(cxtype, i); + typedefC.parameters.add( + Parameter(name: '', type: t.toCodeGenTypeAndDispose()), + ); + } + addToBindings(typedefC); + } + return Type.nativeFunc(name); +} + +/// Generate a unique string for naming in [TypedefC]. +String _getNextUniqueString(String prefix) { + int i = _uniqueStringCounters[prefix] ?? 0; + i++; + _uniqueStringCounters[prefix] = i; + return '${prefix}_$i'; +} + +Map _uniqueStringCounters = {}; diff --git a/lib/src/header_parser/utils.dart b/lib/src/header_parser/utils.dart new file mode 100644 index 00000000..254a9505 --- /dev/null +++ b/lib/src/header_parser/utils.dart @@ -0,0 +1,208 @@ +// Copyright (c) 2020, the Dart project authors. Please see the AUTHORS file +// for details. All rights reserved. Use of this source code is governed by a +// BSD-style license that can be found in the LICENSE file. + +import 'dart:ffi'; + +import 'package:ffi/ffi.dart'; +import 'package:ffigen/src/code_generator.dart'; +import 'package:logging/logging.dart'; + +import 'clang_bindings/clang_bindings.dart' as clang; +import 'data.dart'; +import 'type_extractor/extractor.dart'; + +/// Check [resultCode] of [clang.clang_visitChildren_wrap]. +/// +/// Throws exception if resultCode is not 0. +void visitChildrenResultChecker(int resultCode) { + if (resultCode != 0) { + throw Exception( + 'Exception thrown in a dart function called via C, use --verbose to see more details'); + } +} + +/// Logs the warnings/errors returned by clang for a translation unit. +void logTuDiagnostics( + Pointer tu, + Logger logger, + String header, +) { + final total = clang.clang_getNumDiagnostics(tu); + if (total == 0) { + return; + } + + logger.warning('Header $header: Total errors/warnings: $total.'); + for (var i = 0; i < total; i++) { + final diag = clang.clang_getDiagnostic(tu, i); + final cxstring = clang.clang_formatDiagnostic_wrap( + diag, + clang.CXDiagnosticDisplayOptions.CXDiagnostic_DisplaySourceLocation | + clang.CXDiagnosticDisplayOptions.CXDiagnostic_DisplayColumn | + clang.CXDiagnosticDisplayOptions.CXDiagnostic_DisplayCategoryName, + ); + logger.warning(' ' + cxstring.toStringAndDispose()); + clang.clang_disposeDiagnostic(diag); + } +} + +extension CXCursorExt on Pointer { + /// Returns the kind int from [clang.CXCursorKind]. + int kind() { + return clang.clang_getCursorKind_wrap(this); + } + + /// Name of the cursor (E.g function name, Struct name, Parameter name). + String spelling() { + return clang.clang_getCursorSpelling_wrap(this).toStringAndDispose(); + } + + /// Spelling for a [clang.CXCursorKind], useful for debug purposes. + String kindSpelling() { + return clang + .clang_getCursorKindSpelling_wrap(clang.clang_getCursorKind_wrap(this)) + .toStringAndDispose(); + } + + /// for debug: returns [spelling] [kind] [kindSpelling] [type] [typeSpelling]. + String completeStringRepr() { + final cxtype = type(); + final s = + '(Cursor) spelling: ${spelling()}, kind: ${kind()}, kindSpelling: ${kindSpelling()}, type: ${cxtype.kind()}, typeSpelling: ${cxtype.spelling()}'; + cxtype.dispose(); + return s; + } + + /// Dispose type using [type.dispose]. + Pointer type() { + return clang.clang_getCursorType_wrap(this); + } + + /// Only valid for [clang.CXCursorKind.CXCursor_FunctionDecl]. + /// + /// Dispose type using [type.dispose]. + Pointer returnType() { + final t = type(); + final r = clang.clang_getResultType_wrap(t); + t.dispose(); + return r; + } + + String sourceFileName() { + final cxsource = clang.clang_getCursorLocation_wrap(this); + final cxfilePtr = allocate>(); + final line = allocate(); + final column = allocate(); + final offset = allocate(); + + // Puts the values in these pointers. + clang.clang_getFileLocation_wrap(cxsource, cxfilePtr, line, column, offset); + final s = + clang.clang_getFileName_wrap(cxfilePtr.value).toStringAndDispose(); + free(cxsource); + free(cxfilePtr); + free(line); + free(column); + free(offset); + return s; + } + + void dispose() { + free(this); + } +} + +// TODO(13): Improve generated doc comment. +String getCursorDocComment(Pointer cursor) { + return config.extractComments + ? clang.clang_Cursor_getBriefCommentText_wrap(cursor).toStringAndDispose() + : null; +} + +extension CXTypeExt on Pointer { + /// Get code_gen [Type] representation of [clang.CXType]. + Type toCodeGenType() { + return getCodeGenType(this); + } + + /// Get code_gen [Type] representation of [clang.CXType] and dispose the type. + Type toCodeGenTypeAndDispose() { + final t = getCodeGenType(this); + dispose(); + return t; + } + + /// Spelling for a [clang.CXTypeKind], useful for debug purposes. + String spelling() { + return clang.clang_getTypeSpelling_wrap(this).toStringAndDispose(); + } + + /// Returns the typeKind int from [clang.CXTypeKind]. + int kind() { + return ref.kind; + } + + String kindSpelling() { + return clang.clang_getTypeKindSpelling_wrap(kind()).toStringAndDispose(); + } + + /// For debugging: returns [spelling] [kind] [kindSpelling]. + String completeStringRepr() { + final s = + '(Type) spelling: ${spelling()}, kind: ${kind()}, kindSpelling: ${kindSpelling()}'; + return s; + } + + void dispose() { + free(this); + } +} + +extension CXStringExt on Pointer { + /// Convert CXString to a Dart string + /// + /// Make sure to dispose CXstring using dispose method, or use the + /// [toStringAndDispose] method. + String string() { + String s; + final cstring = clang.clang_getCString_wrap(this); + if (cstring != nullptr) { + s = Utf8.fromUtf8(cstring.cast()); + } + return s; + } + + /// Converts CXString to dart string and disposes CXString. + String toStringAndDispose() { + // Note: clang_getCString_wrap returns a const char *, calling free will result in error. + final s = string(); + clang.clang_disposeString_wrap(this); + return s; + } + + void dispose() { + clang.clang_disposeString_wrap(this); + } +} + +/// Converts a [List] to [Pointer>]. +Pointer> createDynamicStringArray(List list) { + final nativeCmdArgs = allocate>(count: list.length); + + for (var i = 0; i < list.length; i++) { + nativeCmdArgs[i] = Utf8.toUtf8(list[i]); + } + + return nativeCmdArgs; +} + +extension DynamicCStringArray on Pointer> { + // Properly disposes a Pointer, ensure that sure length is correct. + void dispose(int length) { + for (var i = 0; i < length; i++) { + free(this[i]); + } + free(this); + } +} diff --git a/lib/src/strings.dart b/lib/src/strings.dart new file mode 100644 index 00000000..9d9ff17a --- /dev/null +++ b/lib/src/strings.dart @@ -0,0 +1,66 @@ +// Copyright (c) 2020, the Dart project authors. Please see the AUTHORS file +// for details. All rights reserved. Use of this source code is governed by a +// BSD-style license that can be found in the LICENSE file. +import 'package:ffigen/src/header_parser/clang_bindings/clang_bindings.dart' + as clang; + +const output = 'output'; +const libclang_dylib_folder = 'libclang-dylib-folder'; +const headers = 'headers'; +const headerFilter = 'header-filter'; +const compilerOpts = 'compiler-opts'; +const filters = 'filters'; + +// Declarations. +const functions = 'functions'; +const structs = 'structs'; +const enums = 'enums'; + +// Sub-fields of Declarations. +const include = 'include'; +const exclude = 'exclude'; + +// Sub-fields of include/exclude. +const matches = 'matches'; // regex +const names = 'names'; // hashset + +const sizemap = 'size-map'; + +// Sizemap values. +const SChar = 'char'; +const UChar = 'unsigned char'; +const Short = 'short'; +const UShort = 'unsigned short'; +const Int = 'int'; +const UInt = 'unsigned int'; +const Long = 'long'; +const ULong = 'unsigned long'; +const LongLong = 'long long'; +const ULongLong = 'unsigned long long'; +const Enum = 'enum'; + +// Used for validation and extraction of sizemap. +const sizemap_native_mapping = { + SChar: clang.CXTypeKind.CXType_SChar, + UChar: clang.CXTypeKind.CXType_UChar, + Short: clang.CXTypeKind.CXType_Short, + UShort: clang.CXTypeKind.CXType_UShort, + Int: clang.CXTypeKind.CXType_Int, + UInt: clang.CXTypeKind.CXType_UInt, + Long: clang.CXTypeKind.CXType_Long, + ULong: clang.CXTypeKind.CXType_ULong, + LongLong: clang.CXTypeKind.CXType_LongLong, + ULongLong: clang.CXTypeKind.CXType_ULongLong, + Enum: clang.CXTypeKind.CXType_Enum +}; + +// Boolean flags. +const sort = 'sort'; +const useSupportedTypedefs = 'use-supported-typedefs'; +const warnWhenRemoving = 'warn-when-removing'; +const extractComments = 'extract-comments'; + +// Dynamic library names. +const libclang_dylib_linux = 'libwrapped_clang.so'; +const libclang_dylib_macos = 'libwrapped_clang.dylib'; +const libclang_dylib_windows = 'wrapped_clang.dll'; diff --git a/pubspec.yaml b/pubspec.yaml index 7711721d..64ecfbde 100644 --- a/pubspec.yaml +++ b/pubspec.yaml @@ -1,3 +1,7 @@ +# Copyright (c) 2020, the Dart project authors. Please see the AUTHORS file +# for details. All rights reserved. Use of this source code is governed by a +# BSD-style license that can be found in the LICENSE file. + name: ffigen version: 0.0.1 homepage: https://github.com/dart-lang/ffigen @@ -6,7 +10,14 @@ description: Experimental generator for FFI bindings. environment: sdk: '>=2.7.0 <3.0.0' -#dependencies: +dependencies: + ffi: ^0.1.3 + yaml: ^2.2.1 + meta: ^1.1.8 + args: ^1.6.0 + logging: ^0.11.4 + glob: ^1.2.0 + path: ^1.7.0 dev_dependencies: pedantic: ^1.9.0 diff --git a/test/code_generator_test.dart b/test/code_generator_test.dart new file mode 100644 index 00000000..43128372 --- /dev/null +++ b/test/code_generator_test.dart @@ -0,0 +1,646 @@ +// Copyright (c) 2020, the Dart project authors. Please see the AUTHORS file +// for details. All rights reserved. Use of this source code is governed by a +// BSD-style license that can be found in the LICENSE file. + +import 'dart:io'; + +import 'package:ffigen/src/code_generator.dart'; +import 'package:test/test.dart'; + +void main() { + group('code_generator: ', () { + test('Function Binding (primitives, pointers)', () { + final library = Library( + bindings: [ + Func( + name: 'noParam', + dartDoc: 'Just a test function\nheres another line', + returnType: Type.nativeType( + SupportedNativeType.Int32, + ), + ), + Func( + name: 'withPrimitiveParam', + parameters: [ + Parameter( + name: 'a', + type: Type.nativeType( + SupportedNativeType.Int32, + ), + ), + Parameter( + name: 'b', + type: Type.nativeType( + SupportedNativeType.Uint8, + ), + ), + ], + returnType: Type.nativeType( + SupportedNativeType.Char, + ), + ), + Func( + name: 'withPointerParam', + parameters: [ + Parameter( + name: 'a', + type: Type.pointer( + Type.nativeType( + SupportedNativeType.Int32, + ), + ), + ), + Parameter( + name: 'b', + type: Type.pointer( + Type.pointer( + Type.nativeType( + SupportedNativeType.Uint8, + ), + ), + ), + ), + ], + returnType: Type.pointer( + Type.nativeType( + SupportedNativeType.Double, + ), + ), + ), + ], + ); + + final gen = library.generate(); + + // Writing to file for debug purpose. + final file = File( + 'test/debug_generated/Function-Binding-test-output.dart', + ); + try { + expect(gen, '''/// AUTO GENERATED FILE, DO NOT EDIT. +/// +/// Generated by `package:ffigen`. +import 'dart:ffi' as ffi; + +/// Holds the Dynamic library. +ffi.DynamicLibrary _dylib; + +/// Initialises the Dynamic library. +void init(ffi.DynamicLibrary dylib){ + _dylib = dylib; +} +/// Just a test function +/// heres another line +int noParam( +) { + return _noParam( + ); +} + +final _dart_noParam _noParam = _dylib.lookupFunction<_c_noParam,_dart_noParam>('noParam'); + +typedef _c_noParam = ffi.Int32 Function( +); + +typedef _dart_noParam = int Function( +); + +int withPrimitiveParam( + int a, + int b, +) { + return _withPrimitiveParam( + a, + b, + ); +} + +final _dart_withPrimitiveParam _withPrimitiveParam = _dylib.lookupFunction<_c_withPrimitiveParam,_dart_withPrimitiveParam>('withPrimitiveParam'); + +typedef _c_withPrimitiveParam = ffi.Uint8 Function( + ffi.Int32 a, + ffi.Uint8 b, +); + +typedef _dart_withPrimitiveParam = int Function( + int a, + int b, +); + +ffi.Pointer withPointerParam( + ffi.Pointer a, + ffi.Pointer> b, +) { + return _withPointerParam( + a, + b, + ); +} + +final _dart_withPointerParam _withPointerParam = _dylib.lookupFunction<_c_withPointerParam,_dart_withPointerParam>('withPointerParam'); + +typedef _c_withPointerParam = ffi.Pointer Function( + ffi.Pointer a, + ffi.Pointer> b, +); + +typedef _dart_withPointerParam = ffi.Pointer Function( + ffi.Pointer a, + ffi.Pointer> b, +); + +'''); + if (file.existsSync()) { + file.delete(); + } + } catch (e) { + file.writeAsStringSync(gen); + print('Failed test, Debug output: ${file.absolute?.path}'); + rethrow; + } + }); + + test('Struct Binding (primitives, pointers)', () { + final library = Library( + bindings: [ + Struc( + name: 'NoMember', + dartDoc: 'Just a test struct\nheres another line', + ), + Struc( + name: 'WithPrimitiveMember', + members: [ + Member( + name: 'a', + type: Type.nativeType( + SupportedNativeType.Int32, + ), + ), + Member( + name: 'b', + type: Type.nativeType( + SupportedNativeType.Double, + ), + ), + Member( + name: 'c', + type: Type.nativeType( + SupportedNativeType.Char, + ), + ), + ], + ), + Struc( + name: 'WithPointerMember', + members: [ + Member( + name: 'a', + type: Type.pointer( + Type.nativeType( + SupportedNativeType.Int32, + ), + ), + ), + Member( + name: 'b', + type: Type.pointer( + Type.pointer( + Type.nativeType( + SupportedNativeType.Double, + ), + ), + ), + ), + Member( + name: 'c', + type: Type.nativeType( + SupportedNativeType.Char, + ), + ), + ], + ), + ], + ); + + final gen = library.generate(); + + // Writing to file for debug purpose. + final file = File('test/debug_generated/Struct-Binding-test-output.dart'); + + try { + expect(gen, '''/// AUTO GENERATED FILE, DO NOT EDIT. +/// +/// Generated by `package:ffigen`. +import 'dart:ffi' as ffi; + +/// Holds the Dynamic library. +ffi.DynamicLibrary _dylib; + +/// Initialises the Dynamic library. +void init(ffi.DynamicLibrary dylib){ + _dylib = dylib; +} +/// Just a test struct +/// heres another line +class NoMember extends ffi.Struct{ +} + +class WithPrimitiveMember extends ffi.Struct{ + @ffi.Int32() + int a; + + @ffi.Double() + double b; + + @ffi.Uint8() + int c; + +} + +class WithPointerMember extends ffi.Struct{ + ffi.Pointer a; + + ffi.Pointer> b; + + @ffi.Uint8() + int c; + +} + +'''); + if (file.existsSync()) { + file.delete(); + } + } catch (e) { + file.writeAsStringSync(gen); + print('Failed test, Debug output: ${file.absolute?.path}'); + rethrow; + } + }); + + test('Function and Struct Binding (pointer to Struct)', () { + final library = Library( + bindings: [ + Struc( + name: 'SomeStruc', + members: [ + Member( + name: 'a', + type: Type.nativeType( + SupportedNativeType.Int32, + ), + ), + Member( + name: 'b', + type: Type.nativeType( + SupportedNativeType.Double, + ), + ), + Member( + name: 'c', + type: Type.nativeType( + SupportedNativeType.Char, + ), + ), + ], + ), + Func( + name: 'someFunc', + parameters: [ + Parameter( + name: 'some', + type: Type.pointer( + Type.pointer( + Type.struct( + 'SomeStruc', + ), + ), + ), + ), + ], + returnType: Type.pointer( + Type.struct( + 'SomeStruc', + ), + ), + ), + ], + ); + + final gen = library.generate(); + + // Writing to file for debug purpose. + final file = + File('test/debug_generated/Func-n-Struct-Binding-test-output.dart'); + try { + //expect + expect(gen, '''/// AUTO GENERATED FILE, DO NOT EDIT. +/// +/// Generated by `package:ffigen`. +import 'dart:ffi' as ffi; + +/// Holds the Dynamic library. +ffi.DynamicLibrary _dylib; + +/// Initialises the Dynamic library. +void init(ffi.DynamicLibrary dylib){ + _dylib = dylib; +} +class SomeStruc extends ffi.Struct{ + @ffi.Int32() + int a; + + @ffi.Double() + double b; + + @ffi.Uint8() + int c; + +} + +ffi.Pointer someFunc( + ffi.Pointer> some, +) { + return _someFunc( + some, + ); +} + +final _dart_someFunc _someFunc = _dylib.lookupFunction<_c_someFunc,_dart_someFunc>('someFunc'); + +typedef _c_someFunc = ffi.Pointer Function( + ffi.Pointer> some, +); + +typedef _dart_someFunc = ffi.Pointer Function( + ffi.Pointer> some, +); + +'''); + if (file.existsSync()) { + file.delete(); + } + } catch (e) { + file.writeAsStringSync(gen); + print('Failed test, Debug output: ${file.absolute?.path}'); + rethrow; + } + }); + + test('global (primitives, pointers, pointer to struct)', () { + final library = Library( + bindings: [ + Global( + name: 'test1', + type: Type.nativeType( + SupportedNativeType.Int32, + ), + ), + Global( + name: 'test2', + type: Type.pointer( + Type.nativeType( + SupportedNativeType.Float, + ), + ), + ), + Struc( + name: 'Some', + ), + Global( + name: 'test5', + type: Type.pointer( + Type.struct( + 'Some', + ), + ), + ), + ], + ); + + final gen = library.generate(); + + // Writing to file for debug purpose. + final file = File( + 'test/debug_generated/Global-Binding-test-output.dart', + ); + try { + expect(gen, '''/// AUTO GENERATED FILE, DO NOT EDIT. +/// +/// Generated by `package:ffigen`. +import 'dart:ffi' as ffi; + +/// Holds the Dynamic library. +ffi.DynamicLibrary _dylib; + +/// Initialises the Dynamic library. +void init(ffi.DynamicLibrary dylib){ + _dylib = dylib; +} +final int test1 = _dylib.lookup('test1').value; + +final ffi.Pointer test2 = _dylib.lookup>('test2').value; + +class Some extends ffi.Struct{ +} + +final ffi.Pointer test5 = _dylib.lookup>('test5').value; + +'''); + if (file.existsSync()) { + file.delete(); + } + } catch (e) { + file.writeAsStringSync(gen); + print('Failed test, Debug output: ${file.absolute?.path}'); + rethrow; + } + }); + + test('constant', () { + final library = Library( + bindings: [ + Constant( + name: 'test1', + type: Type.nativeType( + SupportedNativeType.Int32, + ), + rawValue: '20', + ), + Constant( + name: 'test2', + type: Type.nativeType( + SupportedNativeType.Float, + ), + rawValue: '20.0', + ), + ], + ); + + final gen = library.generate(); + + // Writing to file for debug purpose. + final file = File( + 'test/debug_generated/Constant-test-output.dart', + ); + try { + expect(gen, '''/// AUTO GENERATED FILE, DO NOT EDIT. +/// +/// Generated by `package:ffigen`. +import 'dart:ffi' as ffi; + +/// Holds the Dynamic library. +ffi.DynamicLibrary _dylib; + +/// Initialises the Dynamic library. +void init(ffi.DynamicLibrary dylib){ + _dylib = dylib; +} +const int test1 = 20; + +const double test2 = 20.0; + +'''); + if (file.existsSync()) { + file.delete(); + } + } catch (e) { + file.writeAsStringSync(gen); + print('Failed test, Debug output: ${file.absolute?.path}'); + rethrow; + } + }); + + test('TypedefC (primitive, pointers, pointer to struct)', () { + final library = Library( + bindings: [ + TypedefC( + dartDoc: 'just a test', + name: 'test1', + returnType: Type.nativeType( + SupportedNativeType.Int32, + ), + ), + Struc(name: 'SomeStruct'), + TypedefC( + name: 'test2', + returnType: Type.pointer( + Type.nativeType( + SupportedNativeType.Int32, + ), + ), + parameters: [ + Parameter( + name: 'param1', + type: Type.pointer( + Type.struct('SomeStruct'), + ), + ), + Parameter( + name: 'param2', + type: Type.nativeType( + SupportedNativeType.Char, + ), + ), + ], + ), + ], + ); + + final gen = library.generate(); + + // Writing to file for debug purpose. + final file = + File('test/debug_generated/typedef-Binding-test-output.dart'); + try { + expect(gen, '''/// AUTO GENERATED FILE, DO NOT EDIT. +/// +/// Generated by `package:ffigen`. +import 'dart:ffi' as ffi; + +/// Holds the Dynamic library. +ffi.DynamicLibrary _dylib; + +/// Initialises the Dynamic library. +void init(ffi.DynamicLibrary dylib){ + _dylib = dylib; +} +/// just a test +typedef test1 = ffi.Int32 Function( +); + +class SomeStruct extends ffi.Struct{ +} + +typedef test2 = ffi.Pointer Function( + ffi.Pointer param1, + ffi.Uint8 param2, +); + +'''); + if (file.existsSync()) { + file.delete(); + } + } catch (e) { + file.writeAsStringSync(gen); + print('Failed test, Debug output: ${file.absolute?.path}'); + rethrow; + } + }); + + test('enum_class', () { + final library = Library( + bindings: [ + EnumClass( + name: 'Constants', + dartDoc: 'test line 1\ntest line 2', + enumConstants: [ + EnumConstant( + name: 'a', + value: 10, + ), + EnumConstant(name: 'b', value: -1, dartDoc: 'negative'), + ], + ), + ], + ); + + final gen = library.generate(); + + // Writing to file for debug purpose. + final file = File( + 'test/debug_generated/enum-class-test-output.dart', + ); + try { + expect(gen, '''/// AUTO GENERATED FILE, DO NOT EDIT. +/// +/// Generated by `package:ffigen`. +import 'dart:ffi' as ffi; + +/// Holds the Dynamic library. +ffi.DynamicLibrary _dylib; + +/// Initialises the Dynamic library. +void init(ffi.DynamicLibrary dylib){ + _dylib = dylib; +} +/// test line 1 +/// test line 2 +class Constants { + static const int a = 10; + /// negative + static const int b = -1; +} + +'''); + if (file.existsSync()) { + file.delete(); + } + } catch (e) { + file.writeAsStringSync(gen); + print('Failed test, Debug output: ${file.absolute?.path}'); + rethrow; + } + }); + }); +} diff --git a/test/header_parser_tests/functions.h b/test/header_parser_tests/functions.h new file mode 100644 index 00000000..306ff0f9 --- /dev/null +++ b/test/header_parser_tests/functions.h @@ -0,0 +1,13 @@ +// Copyright (c) 2020, the Dart project authors. Please see the AUTHORS file +// for details. All rights reserved. Use of this source code is governed by a +// BSD-style license that can be found in the LICENSE file. + +#include + +// Simple tests with primitives. +void func1(); +int32_t func2(int16_t); +double func3(float, int8_t a, int64_t, int32_t b); + +// Tests with pointers to primitives. +void *func4(int8_t **, double, int32_t ***); diff --git a/test/header_parser_tests/functions_test.dart b/test/header_parser_tests/functions_test.dart new file mode 100644 index 00000000..f9e261e8 --- /dev/null +++ b/test/header_parser_tests/functions_test.dart @@ -0,0 +1,145 @@ +// Copyright (c) 2020, the Dart project authors. Please see the AUTHORS file +// for details. All rights reserved. Use of this source code is governed by a +// BSD-style license that can be found in the LICENSE file. + +import 'dart:io'; + +import 'package:ffigen/src/code_generator.dart'; +import 'package:ffigen/src/code_generator/writer.dart'; +import 'package:ffigen/src/header_parser.dart' as parser; +import 'package:ffigen/src/config_provider.dart'; +import 'package:logging/logging.dart'; +import 'package:test/test.dart'; + +final writer = Writer(); + +void main() { + group('header_parser', () { + Library actual, expected; + + setUpAll(() { + expected = expectedLibrary(); + + var dylibPath = 'tool/wrapped_libclang/libwrapped_clang.so'; + if (Platform.isMacOS) { + dylibPath = 'tool/wrapped_libclang/libwrapped_clang.dylib'; + } else if (Platform.isWindows) { + dylibPath = 'tool/wrapped_libclang/wrapped_clang.dll'; + } + + Logger.root.onRecord.listen((log) { + print('${log.level.name.padRight(8)}: ${log.message}'); + }); + + actual = parser.parse( + Config.raw( + libclang_dylib_path: dylibPath, + headers: [ + 'test/header_parser_tests/functions.h', + ], + headerFilter: HeaderFilter( + includedInclusionHeaders: { + 'functions.h', + }, + ), + ), + ); + }); + test('Total bindings count', () { + expect(actual.bindings.length, expected.bindings.length); + }); + + test('func1', () { + expect(binding(actual, 'func1'), binding(expected, 'func1')); + }); + test('func2', () { + expect(binding(actual, 'func2'), binding(expected, 'func2')); + }); + test('func3', () { + expect(binding(actual, 'func3'), binding(expected, 'func3')); + }); + + test('func4', () { + expect(binding(actual, 'func4'), binding(expected, 'func4')); + }); + }); +} + +/// Extracts a binding's string from a library. +String binding(Library lib, String name) { + return lib.bindings + .firstWhere((element) => element.name == name) + .toBindingString(writer) + .string; +} + +Library expectedLibrary() { + return Library( + bindings: [ + Func( + name: 'func1', + returnType: Type.nativeType( + SupportedNativeType.Void, + ), + ), + Func( + name: 'func2', + returnType: Type.nativeType( + SupportedNativeType.Int32, + ), + parameters: [ + Parameter( + name: '', + type: Type.nativeType( + SupportedNativeType.Int16, + ), + ), + ], + ), + Func( + name: 'func3', + returnType: Type.nativeType( + SupportedNativeType.Double, + ), + parameters: [ + Parameter( + type: Type.nativeType( + SupportedNativeType.Float, + ), + ), + Parameter( + name: 'a', + type: Type.nativeType( + SupportedNativeType.Int8, + ), + ), + Parameter( + name: '', + type: Type.nativeType( + SupportedNativeType.Int64, + ), + ), + Parameter( + name: 'b', + type: Type.nativeType( + SupportedNativeType.Int32, + ), + ), + ], + ), + Func( + name: 'func4', + returnType: Type.pointer(Type.nativeType(SupportedNativeType.Void)), + parameters: [ + Parameter( + type: Type.pointer( + Type.pointer(Type.nativeType(SupportedNativeType.Int8)))), + Parameter(type: Type.nativeType(SupportedNativeType.Double)), + Parameter( + type: Type.pointer(Type.pointer( + Type.pointer(Type.nativeType(SupportedNativeType.Int32)))), + ) + ]), + ], + ); +} diff --git a/test/native_functions_test/build_test_dylib.dart b/test/native_functions_test/build_test_dylib.dart new file mode 100644 index 00000000..25258f05 --- /dev/null +++ b/test/native_functions_test/build_test_dylib.dart @@ -0,0 +1,130 @@ +// Copyright (c) 2020, the Dart project authors. Please see the AUTHORS file +// for details. All rights reserved. Use of this source code is governed by a +// BSD-style license that can be found in the LICENSE file. + +/// ======================================================================= +/// ==== Script to generate dynamic library for native_function_tests ===== +/// ======================================================================= +/// This Script effectively calls the following (but user can provide +/// command line args which will replace the defaults shown below)- +/// +/// Linux: +/// ``` +/// clang -shared -fpic native_functions.c -o native_functions.so +/// ``` +/// MacOS: +/// ``` +/// clang -shared -fpic native_functions.c -o native_functions.dylib +/// ``` +/// Windows: +/// ``` +/// call clang -shared native_functions.c -o native_functions.dll -Wl,"/DEF:native_functions.def" +/// del native_functions.exp +/// del native_functions.lib +/// ``` +/// ======================================================================= +/// ======================================================================= +/// ======================================================================= + +import 'dart:io'; + +import 'package:meta/meta.dart'; + +const MACOS = 'macos'; +const WINDOWS = 'windows'; +const LINUX = 'linux'; + +Map platformOptions = { + LINUX: Options( + outputfilename: 'native_functions.so', + sharedFlag: '-shared', + inputHeader: 'native_functions.c', + fPIC: '-fpic', + ), + WINDOWS: Options( + outputfilename: 'native_functions.dll', + sharedFlag: '-shared', + inputHeader: 'native_functions.c', + moduleDefPath: '-Wl,/DEF:native_functions.def', + ), + MACOS: Options( + outputfilename: 'native_functions.dylib', + sharedFlag: '-shared', + inputHeader: 'native_functions.c', + fPIC: '-fpic', + ), +}; + +void main(List arguments) { + print('Building Dynamic Library for Native Tests... '); + final options = getPlatformOptions(); + + // Run clang compiler to generate the dynamic library. + final ProcessResult result = runClangProcess(options); + printSuccess(result, options); +} + +/// Calls the clang compiler. +ProcessResult runClangProcess(Options options) { + final result = Process.runSync( + 'clang', + [ + options.sharedFlag, + options.fPIC, + options.inputHeader, + '-o', + options.outputfilename, + options.moduleDefPath, + ], + ); + return result; +} + +/// Prints success message (or process error if any). +void printSuccess(ProcessResult result, Options options) { + print(result.stdout); + if ((result.stderr as String).isEmpty) { + print('Generated file: ${options.outputfilename}'); + } else { + print(result.stderr); + } +} + +/// Get options based on current platform. +Options getPlatformOptions() { + if (Platform.isMacOS) { + return platformOptions[MACOS]; + } else if (Platform.isWindows) { + return platformOptions[WINDOWS]; + } else if (Platform.isLinux) { + return platformOptions[LINUX]; + } else { + throw Exception('Unknown Platform.'); + } +} + +/// Hold options which would be passed to clang. +class Options { + /// Name of dynamic library to generate. + final String outputfilename; + + /// Tells compiler to generate a shared library. + final String sharedFlag; + + /// Flag for generating Position Independant Code (Not used on windows). + final String fPIC; + + /// Input file. + final String inputHeader; + + /// Path to `.def` file containing symbols to export, windows use only. + final String moduleDefPath; + + Options({ + @required this.outputfilename, + @required this.sharedFlag, + @required this.inputHeader, + this.fPIC = '', + this.moduleDefPath = '', + }); +} diff --git a/test/native_functions_test/config.yaml b/test/native_functions_test/config.yaml new file mode 100644 index 00000000..4af2defb --- /dev/null +++ b/test/native_functions_test/config.yaml @@ -0,0 +1,16 @@ +# Copyright (c) 2020, the Dart project authors. Please see the AUTHORS file +# for details. All rights reserved. Use of this source code is governed by a +# BSD-style license that can be found in the LICENSE file. + +# =================== GENERATING TEST BINDINGS ================== +# dart ../../bin/generate.dart --config config.yaml +# =============================================================== + +output: 'native_functions_bindings.dart' +libclang-dylib-folder: '../../tool/wrapped_libclang' +sort: true +headers: + - 'native_functions.c' +header-filter: + include: + - 'native_functions.c' diff --git a/test/native_functions_test/native_functions.c b/test/native_functions_test/native_functions.c new file mode 100644 index 00000000..544357e3 --- /dev/null +++ b/test/native_functions_test/native_functions.c @@ -0,0 +1,27 @@ +// Copyright (c) 2020, the Dart project authors. Please see the AUTHORS file +// for details. All rights reserved. Use of this source code is governed by a +// BSD-style license that can be found in the LICENSE file. + +#include + +uint8_t Function1Uint8(uint8_t x) { return x + 42; } + +uint16_t Function1Uint16(uint16_t x) { return x + 42; } + +uint32_t Function1Uint32(uint32_t x) { return x + 42; } + +uint64_t Function1Uint64(uint64_t x) { return x + 42; } + +int8_t Function1Int8(int8_t x) { return x + 42; } + +int16_t Function1Int16(int16_t x) { return x + 42; } + +int32_t Function1Int32(int32_t x) { return x + 42; } + +int64_t Function1Int64(int64_t x) { return x + 42; } + +intptr_t Function1IntPtr(intptr_t x) { return x + 42; } + +float Function1Float(float x) { return x + 42.0f; } + +double Function1Double(double x) { return x + 42.0; } diff --git a/test/native_functions_test/native_functions.def b/test/native_functions_test/native_functions.def new file mode 100644 index 00000000..f2d6f914 --- /dev/null +++ b/test/native_functions_test/native_functions.def @@ -0,0 +1,16 @@ +; Copyright (c) 2020, the Dart project authors. Please see the AUTHORS file +; for details. All rights reserved. Use of this source code is governed by a +; BSD-style license that can be found in the LICENSE file. + +EXPORTS +Function1Uint8 +Function1Uint16 +Function1Uint32 +Function1Uint64 +Function1Int8 +Function1Int16 +Function1Int32 +Function1Int64 +Function1IntPtr +Function1Float +Function1Double \ No newline at end of file diff --git a/test/native_functions_test/native_functions_bindings.dart b/test/native_functions_test/native_functions_bindings.dart new file mode 100644 index 00000000..a9eb1e9b --- /dev/null +++ b/test/native_functions_test/native_functions_bindings.dart @@ -0,0 +1,226 @@ +/// AUTO GENERATED FILE, DO NOT EDIT. +/// +/// Generated by `package:ffigen`. +import 'dart:ffi' as ffi; + +/// Holds the Dynamic library. +ffi.DynamicLibrary _dylib; + +/// Initialises the Dynamic library. +void init(ffi.DynamicLibrary dylib) { + _dylib = dylib; +} + +double Function1Double( + double x, +) { + return _Function1Double( + x, + ); +} + +final _dart_Function1Double _Function1Double = + _dylib.lookupFunction<_c_Function1Double, _dart_Function1Double>( + 'Function1Double'); + +typedef _c_Function1Double = ffi.Double Function( + ffi.Double x, +); + +typedef _dart_Function1Double = double Function( + double x, +); + +double Function1Float( + double x, +) { + return _Function1Float( + x, + ); +} + +final _dart_Function1Float _Function1Float = _dylib + .lookupFunction<_c_Function1Float, _dart_Function1Float>('Function1Float'); + +typedef _c_Function1Float = ffi.Float Function( + ffi.Float x, +); + +typedef _dart_Function1Float = double Function( + double x, +); + +int Function1Int16( + int x, +) { + return _Function1Int16( + x, + ); +} + +final _dart_Function1Int16 _Function1Int16 = _dylib + .lookupFunction<_c_Function1Int16, _dart_Function1Int16>('Function1Int16'); + +typedef _c_Function1Int16 = ffi.Int16 Function( + ffi.Int16 x, +); + +typedef _dart_Function1Int16 = int Function( + int x, +); + +int Function1Int32( + int x, +) { + return _Function1Int32( + x, + ); +} + +final _dart_Function1Int32 _Function1Int32 = _dylib + .lookupFunction<_c_Function1Int32, _dart_Function1Int32>('Function1Int32'); + +typedef _c_Function1Int32 = ffi.Int32 Function( + ffi.Int32 x, +); + +typedef _dart_Function1Int32 = int Function( + int x, +); + +int Function1Int64( + int x, +) { + return _Function1Int64( + x, + ); +} + +final _dart_Function1Int64 _Function1Int64 = _dylib + .lookupFunction<_c_Function1Int64, _dart_Function1Int64>('Function1Int64'); + +typedef _c_Function1Int64 = ffi.Int64 Function( + ffi.Int64 x, +); + +typedef _dart_Function1Int64 = int Function( + int x, +); + +int Function1Int8( + int x, +) { + return _Function1Int8( + x, + ); +} + +final _dart_Function1Int8 _Function1Int8 = _dylib + .lookupFunction<_c_Function1Int8, _dart_Function1Int8>('Function1Int8'); + +typedef _c_Function1Int8 = ffi.Int8 Function( + ffi.Int8 x, +); + +typedef _dart_Function1Int8 = int Function( + int x, +); + +int Function1IntPtr( + int x, +) { + return _Function1IntPtr( + x, + ); +} + +final _dart_Function1IntPtr _Function1IntPtr = + _dylib.lookupFunction<_c_Function1IntPtr, _dart_Function1IntPtr>( + 'Function1IntPtr'); + +typedef _c_Function1IntPtr = ffi.IntPtr Function( + ffi.IntPtr x, +); + +typedef _dart_Function1IntPtr = int Function( + int x, +); + +int Function1Uint16( + int x, +) { + return _Function1Uint16( + x, + ); +} + +final _dart_Function1Uint16 _Function1Uint16 = + _dylib.lookupFunction<_c_Function1Uint16, _dart_Function1Uint16>( + 'Function1Uint16'); + +typedef _c_Function1Uint16 = ffi.Uint16 Function( + ffi.Uint16 x, +); + +typedef _dart_Function1Uint16 = int Function( + int x, +); + +int Function1Uint32( + int x, +) { + return _Function1Uint32( + x, + ); +} + +final _dart_Function1Uint32 _Function1Uint32 = + _dylib.lookupFunction<_c_Function1Uint32, _dart_Function1Uint32>( + 'Function1Uint32'); + +typedef _c_Function1Uint32 = ffi.Uint32 Function( + ffi.Uint32 x, +); + +typedef _dart_Function1Uint32 = int Function( + int x, +); + +int Function1Uint64( + int x, +) { + return _Function1Uint64( + x, + ); +} + +final _dart_Function1Uint64 _Function1Uint64 = + _dylib.lookupFunction<_c_Function1Uint64, _dart_Function1Uint64>( + 'Function1Uint64'); + +typedef _c_Function1Uint64 = ffi.Uint64 Function( + ffi.Uint64 x, +); + +typedef _dart_Function1Uint64 = int Function( + int x, +); + +int Function1Uint8( + int x, +) { + return _Function1Uint8( + x, + ); +} + +final _dart_Function1Uint8 _Function1Uint8 = _dylib + .lookupFunction<_c_Function1Uint8, _dart_Function1Uint8>('Function1Uint8'); + +typedef _c_Function1Uint8 = ffi.Uint8 Function( + ffi.Uint8 x, +); + +typedef _dart_Function1Uint8 = int Function( + int x, +); diff --git a/test/native_functions_test/native_functions_test.dart b/test/native_functions_test/native_functions_test.dart new file mode 100644 index 00000000..b63fc35e --- /dev/null +++ b/test/native_functions_test/native_functions_test.dart @@ -0,0 +1,61 @@ +// Copyright (c) 2020, the Dart project authors. Please see the AUTHORS file +// for details. All rights reserved. Use of this source code is governed by a +// BSD-style license that can be found in the LICENSE file. + +import 'dart:ffi'; +import 'dart:io'; +import 'dart:math'; + +import 'package:test/test.dart'; +import 'native_functions_bindings.dart' as bindings; + +void main() { + group('Tests for native functions', () { + setUpAll(() { + var dylibName = 'test/native_functions_test/native_functions.so'; + if (Platform.isMacOS) { + dylibName = 'test/native_functions_test/native_functions.dylib'; + } else if (Platform.isWindows) { + dylibName = r'test\native_functions_test\native_functions.dll'; + } + bindings.init(DynamicLibrary.open(dylibName)); + }); + test('uint8_t', () { + expect(bindings.Function1Uint8(pow(2, 8).toInt()), 42); + }); + test('uint16_t', () { + expect(bindings.Function1Uint16(pow(2, 16).toInt()), 42); + }); + test('uint32_t', () { + expect(bindings.Function1Uint32(pow(2, 32).toInt()), 42); + }); + test('uint64_t', () { + expect(bindings.Function1Uint64(pow(2, 64).toInt()), 42); + }); + test('int8_t', () { + expect( + bindings.Function1Int8(pow(2, 7).toInt()), -pow(2, 7).toInt() + 42); + }); + test('int16_t', () { + expect(bindings.Function1Int16(pow(2, 15).toInt()), + -pow(2, 15).toInt() + 42); + }); + test('int32_t', () { + expect(bindings.Function1Int32(pow(2, 31).toInt()), + -pow(2, 31).toInt() + 42); + }); + test('int64_t', () { + expect(bindings.Function1Int64(pow(2, 63).toInt()), + -pow(2, 63).toInt() + 42); + }); + test('intptr_t', () { + expect(bindings.Function1IntPtr(0), 42); + }); + test('float', () { + expect(bindings.Function1Float(0), 42.0); + }); + test('double', () { + expect(bindings.Function1Double(0), 42.0); + }); + }); +} diff --git a/third_party/cjson_library/.gitignore b/third_party/cjson_library/.gitignore new file mode 100644 index 00000000..53d01a30 --- /dev/null +++ b/third_party/cjson_library/.gitignore @@ -0,0 +1,17 @@ +# CMake generated files and directories. +CMakeCache.txt +CMakeFiles/ +CmakeScripts/ +Makefile +cmake_install.cmake + +# Xcode tooling generated via `cmake -G Xcode .`. +cjson_library.xcodeproj/ + +# Xcode generated build and output directories. +cjson_library.build/ + +# Generated shared library files. +*.dylib +*.so.* +*.dll diff --git a/third_party/cjson_library/CMakeLists.txt b/third_party/cjson_library/CMakeLists.txt new file mode 100644 index 00000000..815ba4fa --- /dev/null +++ b/third_party/cjson_library/CMakeLists.txt @@ -0,0 +1,11 @@ +cmake_minimum_required(VERSION 3.7 FATAL_ERROR) +project(cjson_library VERSION 1.0.0 LANGUAGES C) +add_library(cjson_library SHARED cJSON.c) + +set_target_properties(cjson_library PROPERTIES + PUBLIC_HEADER cJSON.h + VERSION ${PROJECT_VERSION} + SOVERSION 1 + OUTPUT_NAME "cjson" + XCODE_ATTRIBUTE_CODE_SIGN_IDENTITY "Hex_Identity_ID_Goes_Here" +) diff --git a/third_party/cjson_library/cJSON.c b/third_party/cjson_library/cJSON.c new file mode 100644 index 00000000..a198d668 --- /dev/null +++ b/third_party/cjson_library/cJSON.c @@ -0,0 +1,2998 @@ +/* + Copyright (c) 2009-2017 Dave Gamble and cJSON contributors + + Permission is hereby granted, free of charge, to any person obtaining a copy + of this software and associated documentation files (the "Software"), to deal + in the Software without restriction, including without limitation the rights + to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + copies of the Software, and to permit persons to whom the Software is + furnished to do so, subject to the following conditions: + + The above copyright notice and this permission notice shall be included in + all copies or substantial portions of the Software. + + THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + THE SOFTWARE. +*/ + +/* cJSON */ +/* JSON parser in C. */ + +/* disable warnings about old C89 functions in MSVC */ +#if !defined(_CRT_SECURE_NO_DEPRECATE) && defined(_MSC_VER) +#define _CRT_SECURE_NO_DEPRECATE +#endif + +#ifdef __GNUC__ +#pragma GCC visibility push(default) +#endif +#if defined(_MSC_VER) +#pragma warning (push) +/* disable warning about single line comments in system headers */ +#pragma warning (disable : 4001) +#endif + +#include +#include +#include +#include +#include +#include + +#ifdef ENABLE_LOCALES +#include +#endif + +#if defined(_MSC_VER) +#pragma warning (pop) +#endif +#ifdef __GNUC__ +#pragma GCC visibility pop +#endif + +#include "cJSON.h" + +/* define our own boolean type */ +#ifdef true +#undef true +#endif +#define true ((cJSON_bool)1) + +#ifdef false +#undef false +#endif +#define false ((cJSON_bool)0) + +typedef struct { + const unsigned char *json; + size_t position; +} error; +static error global_error = { NULL, 0 }; + +CJSON_PUBLIC(const char *) cJSON_GetErrorPtr(void) +{ + return (const char*) (global_error.json + global_error.position); +} + +CJSON_PUBLIC(char *) cJSON_GetStringValue(const cJSON * const item) { + if (!cJSON_IsString(item)) { + return NULL; + } + + return item->valuestring; +} + +/* This is a safeguard to prevent copy-pasters from using incompatible C and header files */ +#if (CJSON_VERSION_MAJOR != 1) || (CJSON_VERSION_MINOR != 7) || (CJSON_VERSION_PATCH != 12) + #error cJSON.h and cJSON.c have different versions. Make sure that both have the same. +#endif + +CJSON_PUBLIC(const char*) cJSON_Version(void) +{ + static char version[15]; + sprintf(version, "%i.%i.%i", CJSON_VERSION_MAJOR, CJSON_VERSION_MINOR, CJSON_VERSION_PATCH); + + return version; +} + +/* Case insensitive string comparison, doesn't consider two NULL pointers equal though */ +static int case_insensitive_strcmp(const unsigned char *string1, const unsigned char *string2) +{ + if ((string1 == NULL) || (string2 == NULL)) + { + return 1; + } + + if (string1 == string2) + { + return 0; + } + + for(; tolower(*string1) == tolower(*string2); (void)string1++, string2++) + { + if (*string1 == '\0') + { + return 0; + } + } + + return tolower(*string1) - tolower(*string2); +} + +typedef struct internal_hooks +{ + void *(CJSON_CDECL *allocate)(size_t size); + void (CJSON_CDECL *deallocate)(void *pointer); + void *(CJSON_CDECL *reallocate)(void *pointer, size_t size); +} internal_hooks; + +#if defined(_MSC_VER) +/* work around MSVC error C2322: '...' address of dllimport '...' is not static */ +static void * CJSON_CDECL internal_malloc(size_t size) +{ + return malloc(size); +} +static void CJSON_CDECL internal_free(void *pointer) +{ + free(pointer); +} +static void * CJSON_CDECL internal_realloc(void *pointer, size_t size) +{ + return realloc(pointer, size); +} +#else +#define internal_malloc malloc +#define internal_free free +#define internal_realloc realloc +#endif + +/* strlen of character literals resolved at compile time */ +#define static_strlen(string_literal) (sizeof(string_literal) - sizeof("")) + +static internal_hooks global_hooks = { internal_malloc, internal_free, internal_realloc }; + +static unsigned char* cJSON_strdup(const unsigned char* string, const internal_hooks * const hooks) +{ + size_t length = 0; + unsigned char *copy = NULL; + + if (string == NULL) + { + return NULL; + } + + length = strlen((const char*)string) + sizeof(""); + copy = (unsigned char*)hooks->allocate(length); + if (copy == NULL) + { + return NULL; + } + memcpy(copy, string, length); + + return copy; +} + +CJSON_PUBLIC(void) cJSON_InitHooks(cJSON_Hooks* hooks) +{ + if (hooks == NULL) + { + /* Reset hooks */ + global_hooks.allocate = malloc; + global_hooks.deallocate = free; + global_hooks.reallocate = realloc; + return; + } + + global_hooks.allocate = malloc; + if (hooks->malloc_fn != NULL) + { + global_hooks.allocate = hooks->malloc_fn; + } + + global_hooks.deallocate = free; + if (hooks->free_fn != NULL) + { + global_hooks.deallocate = hooks->free_fn; + } + + /* use realloc only if both free and malloc are used */ + global_hooks.reallocate = NULL; + if ((global_hooks.allocate == malloc) && (global_hooks.deallocate == free)) + { + global_hooks.reallocate = realloc; + } +} + +/* Internal constructor. */ +static cJSON *cJSON_New_Item(const internal_hooks * const hooks) +{ + cJSON* node = (cJSON*)hooks->allocate(sizeof(cJSON)); + if (node) + { + memset(node, '\0', sizeof(cJSON)); + } + + return node; +} + +/* Delete a cJSON structure. */ +CJSON_PUBLIC(void) cJSON_Delete(cJSON *item) +{ + cJSON *next = NULL; + while (item != NULL) + { + next = item->next; + if (!(item->type & cJSON_IsReference) && (item->child != NULL)) + { + cJSON_Delete(item->child); + } + if (!(item->type & cJSON_IsReference) && (item->valuestring != NULL)) + { + global_hooks.deallocate(item->valuestring); + } + if (!(item->type & cJSON_StringIsConst) && (item->string != NULL)) + { + global_hooks.deallocate(item->string); + } + global_hooks.deallocate(item); + item = next; + } +} + +/* get the decimal point character of the current locale */ +static unsigned char get_decimal_point(void) +{ +#ifdef ENABLE_LOCALES + struct lconv *lconv = localeconv(); + return (unsigned char) lconv->decimal_point[0]; +#else + return '.'; +#endif +} + +typedef struct +{ + const unsigned char *content; + size_t length; + size_t offset; + size_t depth; /* How deeply nested (in arrays/objects) is the input at the current offset. */ + internal_hooks hooks; +} parse_buffer; + +/* check if the given size is left to read in a given parse buffer (starting with 1) */ +#define can_read(buffer, size) ((buffer != NULL) && (((buffer)->offset + size) <= (buffer)->length)) +/* check if the buffer can be accessed at the given index (starting with 0) */ +#define can_access_at_index(buffer, index) ((buffer != NULL) && (((buffer)->offset + index) < (buffer)->length)) +#define cannot_access_at_index(buffer, index) (!can_access_at_index(buffer, index)) +/* get a pointer to the buffer at the position */ +#define buffer_at_offset(buffer) ((buffer)->content + (buffer)->offset) + +/* Parse the input text to generate a number, and populate the result into item. */ +static cJSON_bool parse_number(cJSON * const item, parse_buffer * const input_buffer) +{ + double number = 0; + unsigned char *after_end = NULL; + unsigned char number_c_string[64]; + unsigned char decimal_point = get_decimal_point(); + size_t i = 0; + + if ((input_buffer == NULL) || (input_buffer->content == NULL)) + { + return false; + } + + /* copy the number into a temporary buffer and replace '.' with the decimal point + * of the current locale (for strtod) + * This also takes care of '\0' not necessarily being available for marking the end of the input */ + for (i = 0; (i < (sizeof(number_c_string) - 1)) && can_access_at_index(input_buffer, i); i++) + { + switch (buffer_at_offset(input_buffer)[i]) + { + case '0': + case '1': + case '2': + case '3': + case '4': + case '5': + case '6': + case '7': + case '8': + case '9': + case '+': + case '-': + case 'e': + case 'E': + number_c_string[i] = buffer_at_offset(input_buffer)[i]; + break; + + case '.': + number_c_string[i] = decimal_point; + break; + + default: + goto loop_end; + } + } +loop_end: + number_c_string[i] = '\0'; + + number = strtod((const char*)number_c_string, (char**)&after_end); + if (number_c_string == after_end) + { + return false; /* parse_error */ + } + + item->valuedouble = number; + + /* use saturation in case of overflow */ + if (number >= INT_MAX) + { + item->valueint = INT_MAX; + } + else if (number <= (double)INT_MIN) + { + item->valueint = INT_MIN; + } + else + { + item->valueint = (int)number; + } + + item->type = cJSON_Number; + + input_buffer->offset += (size_t)(after_end - number_c_string); + return true; +} + +/* don't ask me, but the original cJSON_SetNumberValue returns an integer or double */ +CJSON_PUBLIC(double) cJSON_SetNumberHelper(cJSON *object, double number) +{ + if (number >= INT_MAX) + { + object->valueint = INT_MAX; + } + else if (number <= (double)INT_MIN) + { + object->valueint = INT_MIN; + } + else + { + object->valueint = (int)number; + } + + return object->valuedouble = number; +} + +typedef struct +{ + unsigned char *buffer; + size_t length; + size_t offset; + size_t depth; /* current nesting depth (for formatted printing) */ + cJSON_bool noalloc; + cJSON_bool format; /* is this print a formatted print */ + internal_hooks hooks; +} printbuffer; + +/* realloc printbuffer if necessary to have at least "needed" bytes more */ +static unsigned char* ensure(printbuffer * const p, size_t needed) +{ + unsigned char *newbuffer = NULL; + size_t newsize = 0; + + if ((p == NULL) || (p->buffer == NULL)) + { + return NULL; + } + + if ((p->length > 0) && (p->offset >= p->length)) + { + /* make sure that offset is valid */ + return NULL; + } + + if (needed > INT_MAX) + { + /* sizes bigger than INT_MAX are currently not supported */ + return NULL; + } + + needed += p->offset + 1; + if (needed <= p->length) + { + return p->buffer + p->offset; + } + + if (p->noalloc) { + return NULL; + } + + /* calculate new buffer size */ + if (needed > (INT_MAX / 2)) + { + /* overflow of int, use INT_MAX if possible */ + if (needed <= INT_MAX) + { + newsize = INT_MAX; + } + else + { + return NULL; + } + } + else + { + newsize = needed * 2; + } + + if (p->hooks.reallocate != NULL) + { + /* reallocate with realloc if available */ + newbuffer = (unsigned char*)p->hooks.reallocate(p->buffer, newsize); + if (newbuffer == NULL) + { + p->hooks.deallocate(p->buffer); + p->length = 0; + p->buffer = NULL; + + return NULL; + } + } + else + { + /* otherwise reallocate manually */ + newbuffer = (unsigned char*)p->hooks.allocate(newsize); + if (!newbuffer) + { + p->hooks.deallocate(p->buffer); + p->length = 0; + p->buffer = NULL; + + return NULL; + } + if (newbuffer) + { + memcpy(newbuffer, p->buffer, p->offset + 1); + } + p->hooks.deallocate(p->buffer); + } + p->length = newsize; + p->buffer = newbuffer; + + return newbuffer + p->offset; +} + +/* calculate the new length of the string in a printbuffer and update the offset */ +static void update_offset(printbuffer * const buffer) +{ + const unsigned char *buffer_pointer = NULL; + if ((buffer == NULL) || (buffer->buffer == NULL)) + { + return; + } + buffer_pointer = buffer->buffer + buffer->offset; + + buffer->offset += strlen((const char*)buffer_pointer); +} + +/* securely comparison of floating-point variables */ +static cJSON_bool compare_double(double a, double b) +{ + return (fabs(a - b) <= CJSON_DOUBLE_PRECISION); +} + +/* Render the number nicely from the given item into a string. */ +static cJSON_bool print_number(const cJSON * const item, printbuffer * const output_buffer) +{ + unsigned char *output_pointer = NULL; + double d = item->valuedouble; + int length = 0; + size_t i = 0; + unsigned char number_buffer[26] = {0}; /* temporary buffer to print the number into */ + unsigned char decimal_point = get_decimal_point(); + double test = 0.0; + + if (output_buffer == NULL) + { + return false; + } + + /* This checks for NaN and Infinity */ + if ((d * 0) != 0) + { + length = sprintf((char*)number_buffer, "null"); + } + else + { + /* Try 15 decimal places of precision to avoid nonsignificant nonzero digits */ + length = sprintf((char*)number_buffer, "%1.15g", d); + + /* Check whether the original double can be recovered */ + if ((sscanf((char*)number_buffer, "%lg", &test) != 1) || !compare_double((double)test, d)) + { + /* If not, print with 17 decimal places of precision */ + length = sprintf((char*)number_buffer, "%1.17g", d); + } + } + + /* sprintf failed or buffer overrun occurred */ + if ((length < 0) || (length > (int)(sizeof(number_buffer) - 1))) + { + return false; + } + + /* reserve appropriate space in the output */ + output_pointer = ensure(output_buffer, (size_t)length + sizeof("")); + if (output_pointer == NULL) + { + return false; + } + + /* copy the printed number to the output and replace locale + * dependent decimal point with '.' */ + for (i = 0; i < ((size_t)length); i++) + { + if (number_buffer[i] == decimal_point) + { + output_pointer[i] = '.'; + continue; + } + + output_pointer[i] = number_buffer[i]; + } + output_pointer[i] = '\0'; + + output_buffer->offset += (size_t)length; + + return true; +} + +/* parse 4 digit hexadecimal number */ +static unsigned parse_hex4(const unsigned char * const input) +{ + unsigned int h = 0; + size_t i = 0; + + for (i = 0; i < 4; i++) + { + /* parse digit */ + if ((input[i] >= '0') && (input[i] <= '9')) + { + h += (unsigned int) input[i] - '0'; + } + else if ((input[i] >= 'A') && (input[i] <= 'F')) + { + h += (unsigned int) 10 + input[i] - 'A'; + } + else if ((input[i] >= 'a') && (input[i] <= 'f')) + { + h += (unsigned int) 10 + input[i] - 'a'; + } + else /* invalid */ + { + return 0; + } + + if (i < 3) + { + /* shift left to make place for the next nibble */ + h = h << 4; + } + } + + return h; +} + +/* converts a UTF-16 literal to UTF-8 + * A literal can be one or two sequences of the form \uXXXX */ +static unsigned char utf16_literal_to_utf8(const unsigned char * const input_pointer, const unsigned char * const input_end, unsigned char **output_pointer) +{ + long unsigned int codepoint = 0; + unsigned int first_code = 0; + const unsigned char *first_sequence = input_pointer; + unsigned char utf8_length = 0; + unsigned char utf8_position = 0; + unsigned char sequence_length = 0; + unsigned char first_byte_mark = 0; + + if ((input_end - first_sequence) < 6) + { + /* input ends unexpectedly */ + goto fail; + } + + /* get the first utf16 sequence */ + first_code = parse_hex4(first_sequence + 2); + + /* check that the code is valid */ + if (((first_code >= 0xDC00) && (first_code <= 0xDFFF))) + { + goto fail; + } + + /* UTF16 surrogate pair */ + if ((first_code >= 0xD800) && (first_code <= 0xDBFF)) + { + const unsigned char *second_sequence = first_sequence + 6; + unsigned int second_code = 0; + sequence_length = 12; /* \uXXXX\uXXXX */ + + if ((input_end - second_sequence) < 6) + { + /* input ends unexpectedly */ + goto fail; + } + + if ((second_sequence[0] != '\\') || (second_sequence[1] != 'u')) + { + /* missing second half of the surrogate pair */ + goto fail; + } + + /* get the second utf16 sequence */ + second_code = parse_hex4(second_sequence + 2); + /* check that the code is valid */ + if ((second_code < 0xDC00) || (second_code > 0xDFFF)) + { + /* invalid second half of the surrogate pair */ + goto fail; + } + + + /* calculate the unicode codepoint from the surrogate pair */ + codepoint = 0x10000 + (((first_code & 0x3FF) << 10) | (second_code & 0x3FF)); + } + else + { + sequence_length = 6; /* \uXXXX */ + codepoint = first_code; + } + + /* encode as UTF-8 + * takes at maximum 4 bytes to encode: + * 11110xxx 10xxxxxx 10xxxxxx 10xxxxxx */ + if (codepoint < 0x80) + { + /* normal ascii, encoding 0xxxxxxx */ + utf8_length = 1; + } + else if (codepoint < 0x800) + { + /* two bytes, encoding 110xxxxx 10xxxxxx */ + utf8_length = 2; + first_byte_mark = 0xC0; /* 11000000 */ + } + else if (codepoint < 0x10000) + { + /* three bytes, encoding 1110xxxx 10xxxxxx 10xxxxxx */ + utf8_length = 3; + first_byte_mark = 0xE0; /* 11100000 */ + } + else if (codepoint <= 0x10FFFF) + { + /* four bytes, encoding 1110xxxx 10xxxxxx 10xxxxxx 10xxxxxx */ + utf8_length = 4; + first_byte_mark = 0xF0; /* 11110000 */ + } + else + { + /* invalid unicode codepoint */ + goto fail; + } + + /* encode as utf8 */ + for (utf8_position = (unsigned char)(utf8_length - 1); utf8_position > 0; utf8_position--) + { + /* 10xxxxxx */ + (*output_pointer)[utf8_position] = (unsigned char)((codepoint | 0x80) & 0xBF); + codepoint >>= 6; + } + /* encode first byte */ + if (utf8_length > 1) + { + (*output_pointer)[0] = (unsigned char)((codepoint | first_byte_mark) & 0xFF); + } + else + { + (*output_pointer)[0] = (unsigned char)(codepoint & 0x7F); + } + + *output_pointer += utf8_length; + + return sequence_length; + +fail: + return 0; +} + +/* Parse the input text into an unescaped cinput, and populate item. */ +static cJSON_bool parse_string(cJSON * const item, parse_buffer * const input_buffer) +{ + const unsigned char *input_pointer = buffer_at_offset(input_buffer) + 1; + const unsigned char *input_end = buffer_at_offset(input_buffer) + 1; + unsigned char *output_pointer = NULL; + unsigned char *output = NULL; + + /* not a string */ + if (buffer_at_offset(input_buffer)[0] != '\"') + { + goto fail; + } + + { + /* calculate approximate size of the output (overestimate) */ + size_t allocation_length = 0; + size_t skipped_bytes = 0; + while (((size_t)(input_end - input_buffer->content) < input_buffer->length) && (*input_end != '\"')) + { + /* is escape sequence */ + if (input_end[0] == '\\') + { + if ((size_t)(input_end + 1 - input_buffer->content) >= input_buffer->length) + { + /* prevent buffer overflow when last input character is a backslash */ + goto fail; + } + skipped_bytes++; + input_end++; + } + input_end++; + } + if (((size_t)(input_end - input_buffer->content) >= input_buffer->length) || (*input_end != '\"')) + { + goto fail; /* string ended unexpectedly */ + } + + /* This is at most how much we need for the output */ + allocation_length = (size_t) (input_end - buffer_at_offset(input_buffer)) - skipped_bytes; + output = (unsigned char*)input_buffer->hooks.allocate(allocation_length + sizeof("")); + if (output == NULL) + { + goto fail; /* allocation failure */ + } + } + + output_pointer = output; + /* loop through the string literal */ + while (input_pointer < input_end) + { + if (*input_pointer != '\\') + { + *output_pointer++ = *input_pointer++; + } + /* escape sequence */ + else + { + unsigned char sequence_length = 2; + if ((input_end - input_pointer) < 1) + { + goto fail; + } + + switch (input_pointer[1]) + { + case 'b': + *output_pointer++ = '\b'; + break; + case 'f': + *output_pointer++ = '\f'; + break; + case 'n': + *output_pointer++ = '\n'; + break; + case 'r': + *output_pointer++ = '\r'; + break; + case 't': + *output_pointer++ = '\t'; + break; + case '\"': + case '\\': + case '/': + *output_pointer++ = input_pointer[1]; + break; + + /* UTF-16 literal */ + case 'u': + sequence_length = utf16_literal_to_utf8(input_pointer, input_end, &output_pointer); + if (sequence_length == 0) + { + /* failed to convert UTF16-literal to UTF-8 */ + goto fail; + } + break; + + default: + goto fail; + } + input_pointer += sequence_length; + } + } + + /* zero terminate the output */ + *output_pointer = '\0'; + + item->type = cJSON_String; + item->valuestring = (char*)output; + + input_buffer->offset = (size_t) (input_end - input_buffer->content); + input_buffer->offset++; + + return true; + +fail: + if (output != NULL) + { + input_buffer->hooks.deallocate(output); + } + + if (input_pointer != NULL) + { + input_buffer->offset = (size_t)(input_pointer - input_buffer->content); + } + + return false; +} + +/* Render the cstring provided to an escaped version that can be printed. */ +static cJSON_bool print_string_ptr(const unsigned char * const input, printbuffer * const output_buffer) +{ + const unsigned char *input_pointer = NULL; + unsigned char *output = NULL; + unsigned char *output_pointer = NULL; + size_t output_length = 0; + /* numbers of additional characters needed for escaping */ + size_t escape_characters = 0; + + if (output_buffer == NULL) + { + return false; + } + + /* empty string */ + if (input == NULL) + { + output = ensure(output_buffer, sizeof("\"\"")); + if (output == NULL) + { + return false; + } + strcpy((char*)output, "\"\""); + + return true; + } + + /* set "flag" to 1 if something needs to be escaped */ + for (input_pointer = input; *input_pointer; input_pointer++) + { + switch (*input_pointer) + { + case '\"': + case '\\': + case '\b': + case '\f': + case '\n': + case '\r': + case '\t': + /* one character escape sequence */ + escape_characters++; + break; + default: + if (*input_pointer < 32) + { + /* UTF-16 escape sequence uXXXX */ + escape_characters += 5; + } + break; + } + } + output_length = (size_t)(input_pointer - input) + escape_characters; + + output = ensure(output_buffer, output_length + sizeof("\"\"")); + if (output == NULL) + { + return false; + } + + /* no characters have to be escaped */ + if (escape_characters == 0) + { + output[0] = '\"'; + memcpy(output + 1, input, output_length); + output[output_length + 1] = '\"'; + output[output_length + 2] = '\0'; + + return true; + } + + output[0] = '\"'; + output_pointer = output + 1; + /* copy the string */ + for (input_pointer = input; *input_pointer != '\0'; (void)input_pointer++, output_pointer++) + { + if ((*input_pointer > 31) && (*input_pointer != '\"') && (*input_pointer != '\\')) + { + /* normal character, copy */ + *output_pointer = *input_pointer; + } + else + { + /* character needs to be escaped */ + *output_pointer++ = '\\'; + switch (*input_pointer) + { + case '\\': + *output_pointer = '\\'; + break; + case '\"': + *output_pointer = '\"'; + break; + case '\b': + *output_pointer = 'b'; + break; + case '\f': + *output_pointer = 'f'; + break; + case '\n': + *output_pointer = 'n'; + break; + case '\r': + *output_pointer = 'r'; + break; + case '\t': + *output_pointer = 't'; + break; + default: + /* escape and print as unicode codepoint */ + sprintf((char*)output_pointer, "u%04x", *input_pointer); + output_pointer += 4; + break; + } + } + } + output[output_length + 1] = '\"'; + output[output_length + 2] = '\0'; + + return true; +} + +/* Invoke print_string_ptr (which is useful) on an item. */ +static cJSON_bool print_string(const cJSON * const item, printbuffer * const p) +{ + return print_string_ptr((unsigned char*)item->valuestring, p); +} + +/* Predeclare these prototypes. */ +static cJSON_bool parse_value(cJSON * const item, parse_buffer * const input_buffer); +static cJSON_bool print_value(const cJSON * const item, printbuffer * const output_buffer); +static cJSON_bool parse_array(cJSON * const item, parse_buffer * const input_buffer); +static cJSON_bool print_array(const cJSON * const item, printbuffer * const output_buffer); +static cJSON_bool parse_object(cJSON * const item, parse_buffer * const input_buffer); +static cJSON_bool print_object(const cJSON * const item, printbuffer * const output_buffer); + +/* Utility to jump whitespace and cr/lf */ +static parse_buffer *buffer_skip_whitespace(parse_buffer * const buffer) +{ + if ((buffer == NULL) || (buffer->content == NULL)) + { + return NULL; + } + + while (can_access_at_index(buffer, 0) && (buffer_at_offset(buffer)[0] <= 32)) + { + buffer->offset++; + } + + if (buffer->offset == buffer->length) + { + buffer->offset--; + } + + return buffer; +} + +/* skip the UTF-8 BOM (byte order mark) if it is at the beginning of a buffer */ +static parse_buffer *skip_utf8_bom(parse_buffer * const buffer) +{ + if ((buffer == NULL) || (buffer->content == NULL) || (buffer->offset != 0)) + { + return NULL; + } + + if (can_access_at_index(buffer, 4) && (strncmp((const char*)buffer_at_offset(buffer), "\xEF\xBB\xBF", 3) == 0)) + { + buffer->offset += 3; + } + + return buffer; +} + +/* Parse an object - create a new root, and populate. */ +CJSON_PUBLIC(cJSON *) cJSON_ParseWithOpts(const char *value, const char **return_parse_end, cJSON_bool require_null_terminated) +{ + parse_buffer buffer = { 0, 0, 0, 0, { 0, 0, 0 } }; + cJSON *item = NULL; + + /* reset error position */ + global_error.json = NULL; + global_error.position = 0; + + if (value == NULL) + { + goto fail; + } + + buffer.content = (const unsigned char*)value; + buffer.length = strlen((const char*)value) + sizeof(""); + buffer.offset = 0; + buffer.hooks = global_hooks; + + item = cJSON_New_Item(&global_hooks); + if (item == NULL) /* memory fail */ + { + goto fail; + } + + if (!parse_value(item, buffer_skip_whitespace(skip_utf8_bom(&buffer)))) + { + /* parse failure. ep is set. */ + goto fail; + } + + /* if we require null-terminated JSON without appended garbage, skip and then check for a null terminator */ + if (require_null_terminated) + { + buffer_skip_whitespace(&buffer); + if ((buffer.offset >= buffer.length) || buffer_at_offset(&buffer)[0] != '\0') + { + goto fail; + } + } + if (return_parse_end) + { + *return_parse_end = (const char*)buffer_at_offset(&buffer); + } + + return item; + +fail: + if (item != NULL) + { + cJSON_Delete(item); + } + + if (value != NULL) + { + error local_error; + local_error.json = (const unsigned char*)value; + local_error.position = 0; + + if (buffer.offset < buffer.length) + { + local_error.position = buffer.offset; + } + else if (buffer.length > 0) + { + local_error.position = buffer.length - 1; + } + + if (return_parse_end != NULL) + { + *return_parse_end = (const char*)local_error.json + local_error.position; + } + + global_error = local_error; + } + + return NULL; +} + +/* Default options for cJSON_Parse */ +CJSON_PUBLIC(cJSON *) cJSON_Parse(const char *value) +{ + return cJSON_ParseWithOpts(value, 0, 0); +} + +#define cjson_min(a, b) ((a < b) ? a : b) + +static unsigned char *print(const cJSON * const item, cJSON_bool format, const internal_hooks * const hooks) +{ + static const size_t default_buffer_size = 256; + printbuffer buffer[1]; + unsigned char *printed = NULL; + + memset(buffer, 0, sizeof(buffer)); + + /* create buffer */ + buffer->buffer = (unsigned char*) hooks->allocate(default_buffer_size); + buffer->length = default_buffer_size; + buffer->format = format; + buffer->hooks = *hooks; + if (buffer->buffer == NULL) + { + goto fail; + } + + /* print the value */ + if (!print_value(item, buffer)) + { + goto fail; + } + update_offset(buffer); + + /* check if reallocate is available */ + if (hooks->reallocate != NULL) + { + printed = (unsigned char*) hooks->reallocate(buffer->buffer, buffer->offset + 1); + if (printed == NULL) { + goto fail; + } + buffer->buffer = NULL; + } + else /* otherwise copy the JSON over to a new buffer */ + { + printed = (unsigned char*) hooks->allocate(buffer->offset + 1); + if (printed == NULL) + { + goto fail; + } + memcpy(printed, buffer->buffer, cjson_min(buffer->length, buffer->offset + 1)); + printed[buffer->offset] = '\0'; /* just to be sure */ + + /* free the buffer */ + hooks->deallocate(buffer->buffer); + } + + return printed; + +fail: + if (buffer->buffer != NULL) + { + hooks->deallocate(buffer->buffer); + } + + if (printed != NULL) + { + hooks->deallocate(printed); + } + + return NULL; +} + +/* Render a cJSON item/entity/structure to text. */ +CJSON_PUBLIC(char *) cJSON_Print(const cJSON *item) +{ + return (char*)print(item, true, &global_hooks); +} + +CJSON_PUBLIC(char *) cJSON_PrintUnformatted(const cJSON *item) +{ + return (char*)print(item, false, &global_hooks); +} + +CJSON_PUBLIC(char *) cJSON_PrintBuffered(const cJSON *item, int prebuffer, cJSON_bool fmt) +{ + printbuffer p = { 0, 0, 0, 0, 0, 0, { 0, 0, 0 } }; + + if (prebuffer < 0) + { + return NULL; + } + + p.buffer = (unsigned char*)global_hooks.allocate((size_t)prebuffer); + if (!p.buffer) + { + return NULL; + } + + p.length = (size_t)prebuffer; + p.offset = 0; + p.noalloc = false; + p.format = fmt; + p.hooks = global_hooks; + + if (!print_value(item, &p)) + { + global_hooks.deallocate(p.buffer); + return NULL; + } + + return (char*)p.buffer; +} + +CJSON_PUBLIC(cJSON_bool) cJSON_PrintPreallocated(cJSON *item, char *buffer, const int length, const cJSON_bool format) +{ + printbuffer p = { 0, 0, 0, 0, 0, 0, { 0, 0, 0 } }; + + if ((length < 0) || (buffer == NULL)) + { + return false; + } + + p.buffer = (unsigned char*)buffer; + p.length = (size_t)length; + p.offset = 0; + p.noalloc = true; + p.format = format; + p.hooks = global_hooks; + + return print_value(item, &p); +} + +/* Parser core - when encountering text, process appropriately. */ +static cJSON_bool parse_value(cJSON * const item, parse_buffer * const input_buffer) +{ + if ((input_buffer == NULL) || (input_buffer->content == NULL)) + { + return false; /* no input */ + } + + /* parse the different types of values */ + /* null */ + if (can_read(input_buffer, 4) && (strncmp((const char*)buffer_at_offset(input_buffer), "null", 4) == 0)) + { + item->type = cJSON_NULL; + input_buffer->offset += 4; + return true; + } + /* false */ + if (can_read(input_buffer, 5) && (strncmp((const char*)buffer_at_offset(input_buffer), "false", 5) == 0)) + { + item->type = cJSON_False; + input_buffer->offset += 5; + return true; + } + /* true */ + if (can_read(input_buffer, 4) && (strncmp((const char*)buffer_at_offset(input_buffer), "true", 4) == 0)) + { + item->type = cJSON_True; + item->valueint = 1; + input_buffer->offset += 4; + return true; + } + /* string */ + if (can_access_at_index(input_buffer, 0) && (buffer_at_offset(input_buffer)[0] == '\"')) + { + return parse_string(item, input_buffer); + } + /* number */ + if (can_access_at_index(input_buffer, 0) && ((buffer_at_offset(input_buffer)[0] == '-') || ((buffer_at_offset(input_buffer)[0] >= '0') && (buffer_at_offset(input_buffer)[0] <= '9')))) + { + return parse_number(item, input_buffer); + } + /* array */ + if (can_access_at_index(input_buffer, 0) && (buffer_at_offset(input_buffer)[0] == '[')) + { + return parse_array(item, input_buffer); + } + /* object */ + if (can_access_at_index(input_buffer, 0) && (buffer_at_offset(input_buffer)[0] == '{')) + { + return parse_object(item, input_buffer); + } + + return false; +} + +/* Render a value to text. */ +static cJSON_bool print_value(const cJSON * const item, printbuffer * const output_buffer) +{ + unsigned char *output = NULL; + + if ((item == NULL) || (output_buffer == NULL)) + { + return false; + } + + switch ((item->type) & 0xFF) + { + case cJSON_NULL: + output = ensure(output_buffer, 5); + if (output == NULL) + { + return false; + } + strcpy((char*)output, "null"); + return true; + + case cJSON_False: + output = ensure(output_buffer, 6); + if (output == NULL) + { + return false; + } + strcpy((char*)output, "false"); + return true; + + case cJSON_True: + output = ensure(output_buffer, 5); + if (output == NULL) + { + return false; + } + strcpy((char*)output, "true"); + return true; + + case cJSON_Number: + return print_number(item, output_buffer); + + case cJSON_Raw: + { + size_t raw_length = 0; + if (item->valuestring == NULL) + { + return false; + } + + raw_length = strlen(item->valuestring) + sizeof(""); + output = ensure(output_buffer, raw_length); + if (output == NULL) + { + return false; + } + memcpy(output, item->valuestring, raw_length); + return true; + } + + case cJSON_String: + return print_string(item, output_buffer); + + case cJSON_Array: + return print_array(item, output_buffer); + + case cJSON_Object: + return print_object(item, output_buffer); + + default: + return false; + } +} + +/* Build an array from input text. */ +static cJSON_bool parse_array(cJSON * const item, parse_buffer * const input_buffer) +{ + cJSON *head = NULL; /* head of the linked list */ + cJSON *current_item = NULL; + + if (input_buffer->depth >= CJSON_NESTING_LIMIT) + { + return false; /* to deeply nested */ + } + input_buffer->depth++; + + if (buffer_at_offset(input_buffer)[0] != '[') + { + /* not an array */ + goto fail; + } + + input_buffer->offset++; + buffer_skip_whitespace(input_buffer); + if (can_access_at_index(input_buffer, 0) && (buffer_at_offset(input_buffer)[0] == ']')) + { + /* empty array */ + goto success; + } + + /* check if we skipped to the end of the buffer */ + if (cannot_access_at_index(input_buffer, 0)) + { + input_buffer->offset--; + goto fail; + } + + /* step back to character in front of the first element */ + input_buffer->offset--; + /* loop through the comma separated array elements */ + do + { + /* allocate next item */ + cJSON *new_item = cJSON_New_Item(&(input_buffer->hooks)); + if (new_item == NULL) + { + goto fail; /* allocation failure */ + } + + /* attach next item to list */ + if (head == NULL) + { + /* start the linked list */ + current_item = head = new_item; + } + else + { + /* add to the end and advance */ + current_item->next = new_item; + new_item->prev = current_item; + current_item = new_item; + } + + /* parse next value */ + input_buffer->offset++; + buffer_skip_whitespace(input_buffer); + if (!parse_value(current_item, input_buffer)) + { + goto fail; /* failed to parse value */ + } + buffer_skip_whitespace(input_buffer); + } + while (can_access_at_index(input_buffer, 0) && (buffer_at_offset(input_buffer)[0] == ',')); + + if (cannot_access_at_index(input_buffer, 0) || buffer_at_offset(input_buffer)[0] != ']') + { + goto fail; /* expected end of array */ + } + +success: + input_buffer->depth--; + + item->type = cJSON_Array; + item->child = head; + + input_buffer->offset++; + + return true; + +fail: + if (head != NULL) + { + cJSON_Delete(head); + } + + return false; +} + +/* Render an array to text */ +static cJSON_bool print_array(const cJSON * const item, printbuffer * const output_buffer) +{ + unsigned char *output_pointer = NULL; + size_t length = 0; + cJSON *current_element = item->child; + + if (output_buffer == NULL) + { + return false; + } + + /* Compose the output array. */ + /* opening square bracket */ + output_pointer = ensure(output_buffer, 1); + if (output_pointer == NULL) + { + return false; + } + + *output_pointer = '['; + output_buffer->offset++; + output_buffer->depth++; + + while (current_element != NULL) + { + if (!print_value(current_element, output_buffer)) + { + return false; + } + update_offset(output_buffer); + if (current_element->next) + { + length = (size_t) (output_buffer->format ? 2 : 1); + output_pointer = ensure(output_buffer, length + 1); + if (output_pointer == NULL) + { + return false; + } + *output_pointer++ = ','; + if(output_buffer->format) + { + *output_pointer++ = ' '; + } + *output_pointer = '\0'; + output_buffer->offset += length; + } + current_element = current_element->next; + } + + output_pointer = ensure(output_buffer, 2); + if (output_pointer == NULL) + { + return false; + } + *output_pointer++ = ']'; + *output_pointer = '\0'; + output_buffer->depth--; + + return true; +} + +/* Build an object from the text. */ +static cJSON_bool parse_object(cJSON * const item, parse_buffer * const input_buffer) +{ + cJSON *head = NULL; /* linked list head */ + cJSON *current_item = NULL; + + if (input_buffer->depth >= CJSON_NESTING_LIMIT) + { + return false; /* to deeply nested */ + } + input_buffer->depth++; + + if (cannot_access_at_index(input_buffer, 0) || (buffer_at_offset(input_buffer)[0] != '{')) + { + goto fail; /* not an object */ + } + + input_buffer->offset++; + buffer_skip_whitespace(input_buffer); + if (can_access_at_index(input_buffer, 0) && (buffer_at_offset(input_buffer)[0] == '}')) + { + goto success; /* empty object */ + } + + /* check if we skipped to the end of the buffer */ + if (cannot_access_at_index(input_buffer, 0)) + { + input_buffer->offset--; + goto fail; + } + + /* step back to character in front of the first element */ + input_buffer->offset--; + /* loop through the comma separated array elements */ + do + { + /* allocate next item */ + cJSON *new_item = cJSON_New_Item(&(input_buffer->hooks)); + if (new_item == NULL) + { + goto fail; /* allocation failure */ + } + + /* attach next item to list */ + if (head == NULL) + { + /* start the linked list */ + current_item = head = new_item; + } + else + { + /* add to the end and advance */ + current_item->next = new_item; + new_item->prev = current_item; + current_item = new_item; + } + + /* parse the name of the child */ + input_buffer->offset++; + buffer_skip_whitespace(input_buffer); + if (!parse_string(current_item, input_buffer)) + { + goto fail; /* failed to parse name */ + } + buffer_skip_whitespace(input_buffer); + + /* swap valuestring and string, because we parsed the name */ + current_item->string = current_item->valuestring; + current_item->valuestring = NULL; + + if (cannot_access_at_index(input_buffer, 0) || (buffer_at_offset(input_buffer)[0] != ':')) + { + goto fail; /* invalid object */ + } + + /* parse the value */ + input_buffer->offset++; + buffer_skip_whitespace(input_buffer); + if (!parse_value(current_item, input_buffer)) + { + goto fail; /* failed to parse value */ + } + buffer_skip_whitespace(input_buffer); + } + while (can_access_at_index(input_buffer, 0) && (buffer_at_offset(input_buffer)[0] == ',')); + + if (cannot_access_at_index(input_buffer, 0) || (buffer_at_offset(input_buffer)[0] != '}')) + { + goto fail; /* expected end of object */ + } + +success: + input_buffer->depth--; + + item->type = cJSON_Object; + item->child = head; + + input_buffer->offset++; + return true; + +fail: + if (head != NULL) + { + cJSON_Delete(head); + } + + return false; +} + +/* Render an object to text. */ +static cJSON_bool print_object(const cJSON * const item, printbuffer * const output_buffer) +{ + unsigned char *output_pointer = NULL; + size_t length = 0; + cJSON *current_item = item->child; + + if (output_buffer == NULL) + { + return false; + } + + /* Compose the output: */ + length = (size_t) (output_buffer->format ? 2 : 1); /* fmt: {\n */ + output_pointer = ensure(output_buffer, length + 1); + if (output_pointer == NULL) + { + return false; + } + + *output_pointer++ = '{'; + output_buffer->depth++; + if (output_buffer->format) + { + *output_pointer++ = '\n'; + } + output_buffer->offset += length; + + while (current_item) + { + if (output_buffer->format) + { + size_t i; + output_pointer = ensure(output_buffer, output_buffer->depth); + if (output_pointer == NULL) + { + return false; + } + for (i = 0; i < output_buffer->depth; i++) + { + *output_pointer++ = '\t'; + } + output_buffer->offset += output_buffer->depth; + } + + /* print key */ + if (!print_string_ptr((unsigned char*)current_item->string, output_buffer)) + { + return false; + } + update_offset(output_buffer); + + length = (size_t) (output_buffer->format ? 2 : 1); + output_pointer = ensure(output_buffer, length); + if (output_pointer == NULL) + { + return false; + } + *output_pointer++ = ':'; + if (output_buffer->format) + { + *output_pointer++ = '\t'; + } + output_buffer->offset += length; + + /* print value */ + if (!print_value(current_item, output_buffer)) + { + return false; + } + update_offset(output_buffer); + + /* print comma if not last */ + length = ((size_t)(output_buffer->format ? 1 : 0) + (size_t)(current_item->next ? 1 : 0)); + output_pointer = ensure(output_buffer, length + 1); + if (output_pointer == NULL) + { + return false; + } + if (current_item->next) + { + *output_pointer++ = ','; + } + + if (output_buffer->format) + { + *output_pointer++ = '\n'; + } + *output_pointer = '\0'; + output_buffer->offset += length; + + current_item = current_item->next; + } + + output_pointer = ensure(output_buffer, output_buffer->format ? (output_buffer->depth + 1) : 2); + if (output_pointer == NULL) + { + return false; + } + if (output_buffer->format) + { + size_t i; + for (i = 0; i < (output_buffer->depth - 1); i++) + { + *output_pointer++ = '\t'; + } + } + *output_pointer++ = '}'; + *output_pointer = '\0'; + output_buffer->depth--; + + return true; +} + +/* Get Array size/item / object item. */ +CJSON_PUBLIC(int) cJSON_GetArraySize(const cJSON *array) +{ + cJSON *child = NULL; + size_t size = 0; + + if (array == NULL) + { + return 0; + } + + child = array->child; + + while(child != NULL) + { + size++; + child = child->next; + } + + /* FIXME: Can overflow here. Cannot be fixed without breaking the API */ + + return (int)size; +} + +static cJSON* get_array_item(const cJSON *array, size_t index) +{ + cJSON *current_child = NULL; + + if (array == NULL) + { + return NULL; + } + + current_child = array->child; + while ((current_child != NULL) && (index > 0)) + { + index--; + current_child = current_child->next; + } + + return current_child; +} + +CJSON_PUBLIC(cJSON *) cJSON_GetArrayItem(const cJSON *array, int index) +{ + if (index < 0) + { + return NULL; + } + + return get_array_item(array, (size_t)index); +} + +static cJSON *get_object_item(const cJSON * const object, const char * const name, const cJSON_bool case_sensitive) +{ + cJSON *current_element = NULL; + + if ((object == NULL) || (name == NULL)) + { + return NULL; + } + + current_element = object->child; + if (case_sensitive) + { + while ((current_element != NULL) && (current_element->string != NULL) && (strcmp(name, current_element->string) != 0)) + { + current_element = current_element->next; + } + } + else + { + while ((current_element != NULL) && (case_insensitive_strcmp((const unsigned char*)name, (const unsigned char*)(current_element->string)) != 0)) + { + current_element = current_element->next; + } + } + + if ((current_element == NULL) || (current_element->string == NULL)) { + return NULL; + } + + return current_element; +} + +CJSON_PUBLIC(cJSON *) cJSON_GetObjectItem(const cJSON * const object, const char * const string) +{ + return get_object_item(object, string, false); +} + +CJSON_PUBLIC(cJSON *) cJSON_GetObjectItemCaseSensitive(const cJSON * const object, const char * const string) +{ + return get_object_item(object, string, true); +} + +CJSON_PUBLIC(cJSON_bool) cJSON_HasObjectItem(const cJSON *object, const char *string) +{ + return cJSON_GetObjectItem(object, string) ? 1 : 0; +} + +/* Utility for array list handling. */ +static void suffix_object(cJSON *prev, cJSON *item) +{ + prev->next = item; + item->prev = prev; +} + +/* Utility for handling references. */ +static cJSON *create_reference(const cJSON *item, const internal_hooks * const hooks) +{ + cJSON *reference = NULL; + if (item == NULL) + { + return NULL; + } + + reference = cJSON_New_Item(hooks); + if (reference == NULL) + { + return NULL; + } + + memcpy(reference, item, sizeof(cJSON)); + reference->string = NULL; + reference->type |= cJSON_IsReference; + reference->next = reference->prev = NULL; + return reference; +} + +static cJSON_bool add_item_to_array(cJSON *array, cJSON *item) +{ + cJSON *child = NULL; + + if ((item == NULL) || (array == NULL)) + { + return false; + } + + child = array->child; + /* + * To find the last item int array quickly, we use prev in array + */ + if (child == NULL) + { + /* list is empty, start new one */ + array->child = item; + item->prev = item; + item->next = NULL; + } + else + { + /* append to the end */ + if (child->prev) + { + suffix_object(child->prev, item); + array->child->prev = item; + } + else + { + while (child->next) + { + child = child->next; + } + suffix_object(child, item); + array->child->prev = item; + } + } + return true; +} + +/* Add item to array/object. */ +CJSON_PUBLIC(void) cJSON_AddItemToArray(cJSON *array, cJSON *item) +{ + add_item_to_array(array, item); +} + +#if defined(__clang__) || (defined(__GNUC__) && ((__GNUC__ > 4) || ((__GNUC__ == 4) && (__GNUC_MINOR__ > 5)))) + #pragma GCC diagnostic push +#endif +#ifdef __GNUC__ +#pragma GCC diagnostic ignored "-Wcast-qual" +#endif +/* helper function to cast away const */ +static void* cast_away_const(const void* string) +{ + return (void*)string; +} +#if defined(__clang__) || (defined(__GNUC__) && ((__GNUC__ > 4) || ((__GNUC__ == 4) && (__GNUC_MINOR__ > 5)))) + #pragma GCC diagnostic pop +#endif + + +static cJSON_bool add_item_to_object(cJSON * const object, const char * const string, cJSON * const item, const internal_hooks * const hooks, const cJSON_bool constant_key) +{ + char *new_key = NULL; + int new_type = cJSON_Invalid; + + if ((object == NULL) || (string == NULL) || (item == NULL)) + { + return false; + } + + if (constant_key) + { + new_key = (char*)cast_away_const(string); + new_type = item->type | cJSON_StringIsConst; + } + else + { + new_key = (char*)cJSON_strdup((const unsigned char*)string, hooks); + if (new_key == NULL) + { + return false; + } + + new_type = item->type & ~cJSON_StringIsConst; + } + + if (!(item->type & cJSON_StringIsConst) && (item->string != NULL)) + { + hooks->deallocate(item->string); + } + + item->string = new_key; + item->type = new_type; + + return add_item_to_array(object, item); +} + +CJSON_PUBLIC(void) cJSON_AddItemToObject(cJSON *object, const char *string, cJSON *item) +{ + add_item_to_object(object, string, item, &global_hooks, false); +} + +/* Add an item to an object with constant string as key */ +CJSON_PUBLIC(void) cJSON_AddItemToObjectCS(cJSON *object, const char *string, cJSON *item) +{ + add_item_to_object(object, string, item, &global_hooks, true); +} + +CJSON_PUBLIC(void) cJSON_AddItemReferenceToArray(cJSON *array, cJSON *item) +{ + if (array == NULL) + { + return; + } + + add_item_to_array(array, create_reference(item, &global_hooks)); +} + +CJSON_PUBLIC(void) cJSON_AddItemReferenceToObject(cJSON *object, const char *string, cJSON *item) +{ + if ((object == NULL) || (string == NULL)) + { + return; + } + + add_item_to_object(object, string, create_reference(item, &global_hooks), &global_hooks, false); +} + +CJSON_PUBLIC(cJSON*) cJSON_AddNullToObject(cJSON * const object, const char * const name) +{ + cJSON *null = cJSON_CreateNull(); + if (add_item_to_object(object, name, null, &global_hooks, false)) + { + return null; + } + + cJSON_Delete(null); + return NULL; +} + +CJSON_PUBLIC(cJSON*) cJSON_AddTrueToObject(cJSON * const object, const char * const name) +{ + cJSON *true_item = cJSON_CreateTrue(); + if (add_item_to_object(object, name, true_item, &global_hooks, false)) + { + return true_item; + } + + cJSON_Delete(true_item); + return NULL; +} + +CJSON_PUBLIC(cJSON*) cJSON_AddFalseToObject(cJSON * const object, const char * const name) +{ + cJSON *false_item = cJSON_CreateFalse(); + if (add_item_to_object(object, name, false_item, &global_hooks, false)) + { + return false_item; + } + + cJSON_Delete(false_item); + return NULL; +} + +CJSON_PUBLIC(cJSON*) cJSON_AddBoolToObject(cJSON * const object, const char * const name, const cJSON_bool boolean) +{ + cJSON *bool_item = cJSON_CreateBool(boolean); + if (add_item_to_object(object, name, bool_item, &global_hooks, false)) + { + return bool_item; + } + + cJSON_Delete(bool_item); + return NULL; +} + +CJSON_PUBLIC(cJSON*) cJSON_AddNumberToObject(cJSON * const object, const char * const name, const double number) +{ + cJSON *number_item = cJSON_CreateNumber(number); + if (add_item_to_object(object, name, number_item, &global_hooks, false)) + { + return number_item; + } + + cJSON_Delete(number_item); + return NULL; +} + +CJSON_PUBLIC(cJSON*) cJSON_AddStringToObject(cJSON * const object, const char * const name, const char * const string) +{ + cJSON *string_item = cJSON_CreateString(string); + if (add_item_to_object(object, name, string_item, &global_hooks, false)) + { + return string_item; + } + + cJSON_Delete(string_item); + return NULL; +} + +CJSON_PUBLIC(cJSON*) cJSON_AddRawToObject(cJSON * const object, const char * const name, const char * const raw) +{ + cJSON *raw_item = cJSON_CreateRaw(raw); + if (add_item_to_object(object, name, raw_item, &global_hooks, false)) + { + return raw_item; + } + + cJSON_Delete(raw_item); + return NULL; +} + +CJSON_PUBLIC(cJSON*) cJSON_AddObjectToObject(cJSON * const object, const char * const name) +{ + cJSON *object_item = cJSON_CreateObject(); + if (add_item_to_object(object, name, object_item, &global_hooks, false)) + { + return object_item; + } + + cJSON_Delete(object_item); + return NULL; +} + +CJSON_PUBLIC(cJSON*) cJSON_AddArrayToObject(cJSON * const object, const char * const name) +{ + cJSON *array = cJSON_CreateArray(); + if (add_item_to_object(object, name, array, &global_hooks, false)) + { + return array; + } + + cJSON_Delete(array); + return NULL; +} + +CJSON_PUBLIC(cJSON *) cJSON_DetachItemViaPointer(cJSON *parent, cJSON * const item) +{ + if ((parent == NULL) || (item == NULL)) + { + return NULL; + } + + if (item->prev != NULL) + { + /* not the first element */ + item->prev->next = item->next; + } + if (item->next != NULL) + { + /* not the last element */ + item->next->prev = item->prev; + } + + if (item == parent->child) + { + /* first element */ + parent->child = item->next; + } + /* make sure the detached item doesn't point anywhere anymore */ + item->prev = NULL; + item->next = NULL; + + return item; +} + +CJSON_PUBLIC(cJSON *) cJSON_DetachItemFromArray(cJSON *array, int which) +{ + if (which < 0) + { + return NULL; + } + + return cJSON_DetachItemViaPointer(array, get_array_item(array, (size_t)which)); +} + +CJSON_PUBLIC(void) cJSON_DeleteItemFromArray(cJSON *array, int which) +{ + cJSON_Delete(cJSON_DetachItemFromArray(array, which)); +} + +CJSON_PUBLIC(cJSON *) cJSON_DetachItemFromObject(cJSON *object, const char *string) +{ + cJSON *to_detach = cJSON_GetObjectItem(object, string); + + return cJSON_DetachItemViaPointer(object, to_detach); +} + +CJSON_PUBLIC(cJSON *) cJSON_DetachItemFromObjectCaseSensitive(cJSON *object, const char *string) +{ + cJSON *to_detach = cJSON_GetObjectItemCaseSensitive(object, string); + + return cJSON_DetachItemViaPointer(object, to_detach); +} + +CJSON_PUBLIC(void) cJSON_DeleteItemFromObject(cJSON *object, const char *string) +{ + cJSON_Delete(cJSON_DetachItemFromObject(object, string)); +} + +CJSON_PUBLIC(void) cJSON_DeleteItemFromObjectCaseSensitive(cJSON *object, const char *string) +{ + cJSON_Delete(cJSON_DetachItemFromObjectCaseSensitive(object, string)); +} + +/* Replace array/object items with new ones. */ +CJSON_PUBLIC(void) cJSON_InsertItemInArray(cJSON *array, int which, cJSON *newitem) +{ + cJSON *after_inserted = NULL; + + if (which < 0) + { + return; + } + + after_inserted = get_array_item(array, (size_t)which); + if (after_inserted == NULL) + { + add_item_to_array(array, newitem); + return; + } + + newitem->next = after_inserted; + newitem->prev = after_inserted->prev; + after_inserted->prev = newitem; + if (after_inserted == array->child) + { + array->child = newitem; + } + else + { + newitem->prev->next = newitem; + } +} + +CJSON_PUBLIC(cJSON_bool) cJSON_ReplaceItemViaPointer(cJSON * const parent, cJSON * const item, cJSON * replacement) +{ + if ((parent == NULL) || (replacement == NULL) || (item == NULL)) + { + return false; + } + + if (replacement == item) + { + return true; + } + + replacement->next = item->next; + replacement->prev = item->prev; + + if (replacement->next != NULL) + { + replacement->next->prev = replacement; + } + + if (parent->child == item) + { + parent->child = replacement; + } + else + { /* + * To find the last item int array quickly, we use prev in array. + * We can't modify the last item's next pointer where this item was the parent's child + */ + if (replacement->prev != NULL) + { + replacement->prev->next = replacement; + } + } + + item->next = NULL; + item->prev = NULL; + cJSON_Delete(item); + + return true; +} + +CJSON_PUBLIC(void) cJSON_ReplaceItemInArray(cJSON *array, int which, cJSON *newitem) +{ + if (which < 0) + { + return; + } + + cJSON_ReplaceItemViaPointer(array, get_array_item(array, (size_t)which), newitem); +} + +static cJSON_bool replace_item_in_object(cJSON *object, const char *string, cJSON *replacement, cJSON_bool case_sensitive) +{ + if ((replacement == NULL) || (string == NULL)) + { + return false; + } + + /* replace the name in the replacement */ + if (!(replacement->type & cJSON_StringIsConst) && (replacement->string != NULL)) + { + cJSON_free(replacement->string); + } + replacement->string = (char*)cJSON_strdup((const unsigned char*)string, &global_hooks); + replacement->type &= ~cJSON_StringIsConst; + + cJSON_ReplaceItemViaPointer(object, get_object_item(object, string, case_sensitive), replacement); + + return true; +} + +CJSON_PUBLIC(void) cJSON_ReplaceItemInObject(cJSON *object, const char *string, cJSON *newitem) +{ + replace_item_in_object(object, string, newitem, false); +} + +CJSON_PUBLIC(void) cJSON_ReplaceItemInObjectCaseSensitive(cJSON *object, const char *string, cJSON *newitem) +{ + replace_item_in_object(object, string, newitem, true); +} + +/* Create basic types: */ +CJSON_PUBLIC(cJSON *) cJSON_CreateNull(void) +{ + cJSON *item = cJSON_New_Item(&global_hooks); + if(item) + { + item->type = cJSON_NULL; + } + + return item; +} + +CJSON_PUBLIC(cJSON *) cJSON_CreateTrue(void) +{ + cJSON *item = cJSON_New_Item(&global_hooks); + if(item) + { + item->type = cJSON_True; + } + + return item; +} + +CJSON_PUBLIC(cJSON *) cJSON_CreateFalse(void) +{ + cJSON *item = cJSON_New_Item(&global_hooks); + if(item) + { + item->type = cJSON_False; + } + + return item; +} + +CJSON_PUBLIC(cJSON *) cJSON_CreateBool(cJSON_bool boolean) +{ + cJSON *item = cJSON_New_Item(&global_hooks); + if(item) + { + item->type = boolean ? cJSON_True : cJSON_False; + } + + return item; +} + +CJSON_PUBLIC(cJSON *) cJSON_CreateNumber(double num) +{ + cJSON *item = cJSON_New_Item(&global_hooks); + if(item) + { + item->type = cJSON_Number; + item->valuedouble = num; + + /* use saturation in case of overflow */ + if (num >= INT_MAX) + { + item->valueint = INT_MAX; + } + else if (num <= (double)INT_MIN) + { + item->valueint = INT_MIN; + } + else + { + item->valueint = (int)num; + } + } + + return item; +} + +CJSON_PUBLIC(cJSON *) cJSON_CreateString(const char *string) +{ + cJSON *item = cJSON_New_Item(&global_hooks); + if(item) + { + item->type = cJSON_String; + item->valuestring = (char*)cJSON_strdup((const unsigned char*)string, &global_hooks); + if(!item->valuestring) + { + cJSON_Delete(item); + return NULL; + } + } + + return item; +} + +CJSON_PUBLIC(cJSON *) cJSON_CreateStringReference(const char *string) +{ + cJSON *item = cJSON_New_Item(&global_hooks); + if (item != NULL) + { + item->type = cJSON_String | cJSON_IsReference; + item->valuestring = (char*)cast_away_const(string); + } + + return item; +} + +CJSON_PUBLIC(cJSON *) cJSON_CreateObjectReference(const cJSON *child) +{ + cJSON *item = cJSON_New_Item(&global_hooks); + if (item != NULL) { + item->type = cJSON_Object | cJSON_IsReference; + item->child = (cJSON*)cast_away_const(child); + } + + return item; +} + +CJSON_PUBLIC(cJSON *) cJSON_CreateArrayReference(const cJSON *child) { + cJSON *item = cJSON_New_Item(&global_hooks); + if (item != NULL) { + item->type = cJSON_Array | cJSON_IsReference; + item->child = (cJSON*)cast_away_const(child); + } + + return item; +} + +CJSON_PUBLIC(cJSON *) cJSON_CreateRaw(const char *raw) +{ + cJSON *item = cJSON_New_Item(&global_hooks); + if(item) + { + item->type = cJSON_Raw; + item->valuestring = (char*)cJSON_strdup((const unsigned char*)raw, &global_hooks); + if(!item->valuestring) + { + cJSON_Delete(item); + return NULL; + } + } + + return item; +} + +CJSON_PUBLIC(cJSON *) cJSON_CreateArray(void) +{ + cJSON *item = cJSON_New_Item(&global_hooks); + if(item) + { + item->type=cJSON_Array; + } + + return item; +} + +CJSON_PUBLIC(cJSON *) cJSON_CreateObject(void) +{ + cJSON *item = cJSON_New_Item(&global_hooks); + if (item) + { + item->type = cJSON_Object; + } + + return item; +} + +/* Create Arrays: */ +CJSON_PUBLIC(cJSON *) cJSON_CreateIntArray(const int *numbers, int count) +{ + size_t i = 0; + cJSON *n = NULL; + cJSON *p = NULL; + cJSON *a = NULL; + + if ((count < 0) || (numbers == NULL)) + { + return NULL; + } + + a = cJSON_CreateArray(); + for(i = 0; a && (i < (size_t)count); i++) + { + n = cJSON_CreateNumber(numbers[i]); + if (!n) + { + cJSON_Delete(a); + return NULL; + } + if(!i) + { + a->child = n; + } + else + { + suffix_object(p, n); + } + p = n; + } + + return a; +} + +CJSON_PUBLIC(cJSON *) cJSON_CreateFloatArray(const float *numbers, int count) +{ + size_t i = 0; + cJSON *n = NULL; + cJSON *p = NULL; + cJSON *a = NULL; + + if ((count < 0) || (numbers == NULL)) + { + return NULL; + } + + a = cJSON_CreateArray(); + + for(i = 0; a && (i < (size_t)count); i++) + { + n = cJSON_CreateNumber((double)numbers[i]); + if(!n) + { + cJSON_Delete(a); + return NULL; + } + if(!i) + { + a->child = n; + } + else + { + suffix_object(p, n); + } + p = n; + } + + return a; +} + +CJSON_PUBLIC(cJSON *) cJSON_CreateDoubleArray(const double *numbers, int count) +{ + size_t i = 0; + cJSON *n = NULL; + cJSON *p = NULL; + cJSON *a = NULL; + + if ((count < 0) || (numbers == NULL)) + { + return NULL; + } + + a = cJSON_CreateArray(); + + for(i = 0;a && (i < (size_t)count); i++) + { + n = cJSON_CreateNumber(numbers[i]); + if(!n) + { + cJSON_Delete(a); + return NULL; + } + if(!i) + { + a->child = n; + } + else + { + suffix_object(p, n); + } + p = n; + } + + return a; +} + +CJSON_PUBLIC(cJSON *) cJSON_CreateStringArray(const char *const *strings, int count) +{ + size_t i = 0; + cJSON *n = NULL; + cJSON *p = NULL; + cJSON *a = NULL; + + if ((count < 0) || (strings == NULL)) + { + return NULL; + } + + a = cJSON_CreateArray(); + + for (i = 0; a && (i < (size_t)count); i++) + { + n = cJSON_CreateString(strings[i]); + if(!n) + { + cJSON_Delete(a); + return NULL; + } + if(!i) + { + a->child = n; + } + else + { + suffix_object(p,n); + } + p = n; + } + + return a; +} + +/* Duplication */ +CJSON_PUBLIC(cJSON *) cJSON_Duplicate(const cJSON *item, cJSON_bool recurse) +{ + cJSON *newitem = NULL; + cJSON *child = NULL; + cJSON *next = NULL; + cJSON *newchild = NULL; + + /* Bail on bad ptr */ + if (!item) + { + goto fail; + } + /* Create new item */ + newitem = cJSON_New_Item(&global_hooks); + if (!newitem) + { + goto fail; + } + /* Copy over all vars */ + newitem->type = item->type & (~cJSON_IsReference); + newitem->valueint = item->valueint; + newitem->valuedouble = item->valuedouble; + if (item->valuestring) + { + newitem->valuestring = (char*)cJSON_strdup((unsigned char*)item->valuestring, &global_hooks); + if (!newitem->valuestring) + { + goto fail; + } + } + if (item->string) + { + newitem->string = (item->type&cJSON_StringIsConst) ? item->string : (char*)cJSON_strdup((unsigned char*)item->string, &global_hooks); + if (!newitem->string) + { + goto fail; + } + } + /* If non-recursive, then we're done! */ + if (!recurse) + { + return newitem; + } + /* Walk the ->next chain for the child. */ + child = item->child; + while (child != NULL) + { + newchild = cJSON_Duplicate(child, true); /* Duplicate (with recurse) each item in the ->next chain */ + if (!newchild) + { + goto fail; + } + if (next != NULL) + { + /* If newitem->child already set, then crosswire ->prev and ->next and move on */ + next->next = newchild; + newchild->prev = next; + next = newchild; + } + else + { + /* Set newitem->child and move to it */ + newitem->child = newchild; + next = newchild; + } + child = child->next; + } + + return newitem; + +fail: + if (newitem != NULL) + { + cJSON_Delete(newitem); + } + + return NULL; +} + +static void skip_oneline_comment(char **input) +{ + *input += static_strlen("//"); + + for (; (*input)[0] != '\0'; ++(*input)) + { + if ((*input)[0] == '\n') { + *input += static_strlen("\n"); + return; + } + } +} + +static void skip_multiline_comment(char **input) +{ + *input += static_strlen("/*"); + + for (; (*input)[0] != '\0'; ++(*input)) + { + if (((*input)[0] == '*') && ((*input)[1] == '/')) + { + *input += static_strlen("*/"); + return; + } + } +} + +static void minify_string(char **input, char **output) { + (*output)[0] = (*input)[0]; + *input += static_strlen("\""); + *output += static_strlen("\""); + + + for (; (*input)[0] != '\0'; (void)++(*input), ++(*output)) { + (*output)[0] = (*input)[0]; + + if ((*input)[0] == '\"') { + (*output)[0] = '\"'; + *input += static_strlen("\""); + *output += static_strlen("\""); + return; + } else if (((*input)[0] == '\\') && ((*input)[1] == '\"')) { + (*output)[1] = (*input)[1]; + *input += static_strlen("\""); + *output += static_strlen("\""); + } + } +} + +CJSON_PUBLIC(void) cJSON_Minify(char *json) +{ + char *into = json; + + if (json == NULL) + { + return; + } + + while (json[0] != '\0') + { + switch (json[0]) + { + case ' ': + case '\t': + case '\r': + case '\n': + json++; + break; + + case '/': + if (json[1] == '/') + { + skip_oneline_comment(&json); + } + else if (json[1] == '*') + { + skip_multiline_comment(&json); + } else { + json++; + } + break; + + case '\"': + minify_string(&json, (char**)&into); + break; + + default: + into[0] = json[0]; + json++; + into++; + } + } + + /* and null-terminate. */ + *into = '\0'; +} + +CJSON_PUBLIC(cJSON_bool) cJSON_IsInvalid(const cJSON * const item) +{ + if (item == NULL) + { + return false; + } + + return (item->type & 0xFF) == cJSON_Invalid; +} + +CJSON_PUBLIC(cJSON_bool) cJSON_IsFalse(const cJSON * const item) +{ + if (item == NULL) + { + return false; + } + + return (item->type & 0xFF) == cJSON_False; +} + +CJSON_PUBLIC(cJSON_bool) cJSON_IsTrue(const cJSON * const item) +{ + if (item == NULL) + { + return false; + } + + return (item->type & 0xff) == cJSON_True; +} + + +CJSON_PUBLIC(cJSON_bool) cJSON_IsBool(const cJSON * const item) +{ + if (item == NULL) + { + return false; + } + + return (item->type & (cJSON_True | cJSON_False)) != 0; +} +CJSON_PUBLIC(cJSON_bool) cJSON_IsNull(const cJSON * const item) +{ + if (item == NULL) + { + return false; + } + + return (item->type & 0xFF) == cJSON_NULL; +} + +CJSON_PUBLIC(cJSON_bool) cJSON_IsNumber(const cJSON * const item) +{ + if (item == NULL) + { + return false; + } + + return (item->type & 0xFF) == cJSON_Number; +} + +CJSON_PUBLIC(cJSON_bool) cJSON_IsString(const cJSON * const item) +{ + if (item == NULL) + { + return false; + } + + return (item->type & 0xFF) == cJSON_String; +} + +CJSON_PUBLIC(cJSON_bool) cJSON_IsArray(const cJSON * const item) +{ + if (item == NULL) + { + return false; + } + + return (item->type & 0xFF) == cJSON_Array; +} + +CJSON_PUBLIC(cJSON_bool) cJSON_IsObject(const cJSON * const item) +{ + if (item == NULL) + { + return false; + } + + return (item->type & 0xFF) == cJSON_Object; +} + +CJSON_PUBLIC(cJSON_bool) cJSON_IsRaw(const cJSON * const item) +{ + if (item == NULL) + { + return false; + } + + return (item->type & 0xFF) == cJSON_Raw; +} + +CJSON_PUBLIC(cJSON_bool) cJSON_Compare(const cJSON * const a, const cJSON * const b, const cJSON_bool case_sensitive) +{ + if ((a == NULL) || (b == NULL) || ((a->type & 0xFF) != (b->type & 0xFF)) || cJSON_IsInvalid(a)) + { + return false; + } + + /* check if type is valid */ + switch (a->type & 0xFF) + { + case cJSON_False: + case cJSON_True: + case cJSON_NULL: + case cJSON_Number: + case cJSON_String: + case cJSON_Raw: + case cJSON_Array: + case cJSON_Object: + break; + + default: + return false; + } + + /* identical objects are equal */ + if (a == b) + { + return true; + } + + switch (a->type & 0xFF) + { + /* in these cases and equal type is enough */ + case cJSON_False: + case cJSON_True: + case cJSON_NULL: + return true; + + case cJSON_Number: + if (compare_double(a->valuedouble, b->valuedouble)) + { + return true; + } + return false; + + case cJSON_String: + case cJSON_Raw: + if ((a->valuestring == NULL) || (b->valuestring == NULL)) + { + return false; + } + if (strcmp(a->valuestring, b->valuestring) == 0) + { + return true; + } + + return false; + + case cJSON_Array: + { + cJSON *a_element = a->child; + cJSON *b_element = b->child; + + for (; (a_element != NULL) && (b_element != NULL);) + { + if (!cJSON_Compare(a_element, b_element, case_sensitive)) + { + return false; + } + + a_element = a_element->next; + b_element = b_element->next; + } + + /* one of the arrays is longer than the other */ + if (a_element != b_element) { + return false; + } + + return true; + } + + case cJSON_Object: + { + cJSON *a_element = NULL; + cJSON *b_element = NULL; + cJSON_ArrayForEach(a_element, a) + { + /* TODO This has O(n^2) runtime, which is horrible! */ + b_element = get_object_item(b, a_element->string, case_sensitive); + if (b_element == NULL) + { + return false; + } + + if (!cJSON_Compare(a_element, b_element, case_sensitive)) + { + return false; + } + } + + /* doing this twice, once on a and b to prevent true comparison if a subset of b + * TODO: Do this the proper way, this is just a fix for now */ + cJSON_ArrayForEach(b_element, b) + { + a_element = get_object_item(a, b_element->string, case_sensitive); + if (a_element == NULL) + { + return false; + } + + if (!cJSON_Compare(b_element, a_element, case_sensitive)) + { + return false; + } + } + + return true; + } + + default: + return false; + } +} + +CJSON_PUBLIC(void *) cJSON_malloc(size_t size) +{ + return global_hooks.allocate(size); +} + +CJSON_PUBLIC(void) cJSON_free(void *object) +{ + global_hooks.deallocate(object); +} diff --git a/third_party/cjson_library/cJSON.h b/third_party/cjson_library/cJSON.h new file mode 100644 index 00000000..9d28b244 --- /dev/null +++ b/third_party/cjson_library/cJSON.h @@ -0,0 +1,292 @@ +/* + Copyright (c) 2009-2017 Dave Gamble and cJSON contributors + + Permission is hereby granted, free of charge, to any person obtaining a copy + of this software and associated documentation files (the "Software"), to deal + in the Software without restriction, including without limitation the rights + to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + copies of the Software, and to permit persons to whom the Software is + furnished to do so, subject to the following conditions: + + The above copyright notice and this permission notice shall be included in + all copies or substantial portions of the Software. + + THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + THE SOFTWARE. +*/ +#ifndef cJSON__h +#define cJSON__h + +#ifdef __cplusplus +extern "C" +{ +#endif + +#if !defined(__WINDOWS__) && (defined(WIN32) || defined(WIN64) || defined(_MSC_VER) || defined(_WIN32)) +#define __WINDOWS__ +#endif + +#ifdef __WINDOWS__ + +/* When compiling for windows, we specify a specific calling convention to avoid issues where we are being called from a project with a different default calling convention. For windows you have 3 define options: + +CJSON_HIDE_SYMBOLS - Define this in the case where you don't want to ever dllexport symbols +CJSON_EXPORT_SYMBOLS - Define this on library build when you want to dllexport symbols (default) +CJSON_IMPORT_SYMBOLS - Define this if you want to dllimport symbol + +For *nix builds that support visibility attribute, you can define similar behavior by + +setting default visibility to hidden by adding +-fvisibility=hidden (for gcc) +or +-xldscope=hidden (for sun cc) +to CFLAGS + +then using the CJSON_API_VISIBILITY flag to "export" the same symbols the way CJSON_EXPORT_SYMBOLS does + +*/ + +#define CJSON_CDECL __cdecl +#define CJSON_STDCALL __stdcall + +/* export symbols by default, this is necessary for copy pasting the C and header file */ +#if !defined(CJSON_HIDE_SYMBOLS) && !defined(CJSON_IMPORT_SYMBOLS) && !defined(CJSON_EXPORT_SYMBOLS) +#define CJSON_EXPORT_SYMBOLS +#endif + +#if defined(CJSON_HIDE_SYMBOLS) +#define CJSON_PUBLIC(type) type CJSON_STDCALL +#elif defined(CJSON_EXPORT_SYMBOLS) +#define CJSON_PUBLIC(type) __declspec(dllexport) type CJSON_STDCALL +#elif defined(CJSON_IMPORT_SYMBOLS) +#define CJSON_PUBLIC(type) __declspec(dllimport) type CJSON_STDCALL +#endif +#else /* !__WINDOWS__ */ +#define CJSON_CDECL +#define CJSON_STDCALL + +#if (defined(__GNUC__) || defined(__SUNPRO_CC) || defined (__SUNPRO_C)) && defined(CJSON_API_VISIBILITY) +#define CJSON_PUBLIC(type) __attribute__((visibility("default"))) type +#else +#define CJSON_PUBLIC(type) type +#endif +#endif + +/* project version */ +#define CJSON_VERSION_MAJOR 1 +#define CJSON_VERSION_MINOR 7 +#define CJSON_VERSION_PATCH 12 + +#include + +/* cJSON Types: */ +#define cJSON_Invalid (0) +#define cJSON_False (1 << 0) +#define cJSON_True (1 << 1) +#define cJSON_NULL (1 << 2) +#define cJSON_Number (1 << 3) +#define cJSON_String (1 << 4) +#define cJSON_Array (1 << 5) +#define cJSON_Object (1 << 6) +#define cJSON_Raw (1 << 7) /* raw json */ + +#define cJSON_IsReference 256 +#define cJSON_StringIsConst 512 + +/* The cJSON structure: */ +typedef struct cJSON +{ + /* next/prev allow you to walk array/object chains. Alternatively, use GetArraySize/GetArrayItem/GetObjectItem */ + struct cJSON *next; + struct cJSON *prev; + /* An array or object item will have a child pointer pointing to a chain of the items in the array/object. */ + struct cJSON *child; + + /* The type of the item, as above. */ + int type; + + /* The item's string, if type==cJSON_String and type == cJSON_Raw */ + char *valuestring; + /* writing to valueint is DEPRECATED, use cJSON_SetNumberValue instead */ + int valueint; + /* The item's number, if type==cJSON_Number */ + double valuedouble; + + /* The item's name string, if this item is the child of, or is in the list of subitems of an object. */ + char *string; +} cJSON; + +typedef struct cJSON_Hooks +{ + /* malloc/free are CDECL on Windows regardless of the default calling convention of the compiler, so ensure the hooks allow passing those functions directly. */ + void *(CJSON_CDECL *malloc_fn)(size_t sz); + void (CJSON_CDECL *free_fn)(void *ptr); +} cJSON_Hooks; + +typedef int cJSON_bool; + +/* Limits how deeply nested arrays/objects can be before cJSON rejects to parse them. + * This is to prevent stack overflows. */ +#ifndef CJSON_NESTING_LIMIT +#define CJSON_NESTING_LIMIT 1000 +#endif + +/* Precision of double variables comparison */ +#ifndef CJSON_DOUBLE_PRECISION +#define CJSON_DOUBLE_PRECISION .0000000000000001 +#endif + +/* returns the version of cJSON as a string */ +CJSON_PUBLIC(const char*) cJSON_Version(void); + +/* Supply malloc, realloc and free functions to cJSON */ +CJSON_PUBLIC(void) cJSON_InitHooks(cJSON_Hooks* hooks); + +/* Memory Management: the caller is always responsible to free the results from all variants of cJSON_Parse (with cJSON_Delete) and cJSON_Print (with stdlib free, cJSON_Hooks.free_fn, or cJSON_free as appropriate). The exception is cJSON_PrintPreallocated, where the caller has full responsibility of the buffer. */ +/* Supply a block of JSON, and this returns a cJSON object you can interrogate. */ +CJSON_PUBLIC(cJSON *) cJSON_Parse(const char *value); +/* ParseWithOpts allows you to require (and check) that the JSON is null terminated, and to retrieve the pointer to the final byte parsed. */ +/* If you supply a ptr in return_parse_end and parsing fails, then return_parse_end will contain a pointer to the error so will match cJSON_GetErrorPtr(). */ +CJSON_PUBLIC(cJSON *) cJSON_ParseWithOpts(const char *value, const char **return_parse_end, cJSON_bool require_null_terminated); + +/* Render a cJSON entity to text for transfer/storage. */ +CJSON_PUBLIC(char *) cJSON_Print(const cJSON *item); +/* Render a cJSON entity to text for transfer/storage without any formatting. */ +CJSON_PUBLIC(char *) cJSON_PrintUnformatted(const cJSON *item); +/* Render a cJSON entity to text using a buffered strategy. prebuffer is a guess at the final size. guessing well reduces reallocation. fmt=0 gives unformatted, =1 gives formatted */ +CJSON_PUBLIC(char *) cJSON_PrintBuffered(const cJSON *item, int prebuffer, cJSON_bool fmt); +/* Render a cJSON entity to text using a buffer already allocated in memory with given length. Returns 1 on success and 0 on failure. */ +/* NOTE: cJSON is not always 100% accurate in estimating how much memory it will use, so to be safe allocate 5 bytes more than you actually need */ +CJSON_PUBLIC(cJSON_bool) cJSON_PrintPreallocated(cJSON *item, char *buffer, const int length, const cJSON_bool format); +/* Delete a cJSON entity and all subentities. */ +CJSON_PUBLIC(void) cJSON_Delete(cJSON *item); + +/* Returns the number of items in an array (or object). */ +CJSON_PUBLIC(int) cJSON_GetArraySize(const cJSON *array); +/* Retrieve item number "index" from array "array". Returns NULL if unsuccessful. */ +CJSON_PUBLIC(cJSON *) cJSON_GetArrayItem(const cJSON *array, int index); +/* Get item "string" from object. Case insensitive. */ +CJSON_PUBLIC(cJSON *) cJSON_GetObjectItem(const cJSON * const object, const char * const string); +CJSON_PUBLIC(cJSON *) cJSON_GetObjectItemCaseSensitive(const cJSON * const object, const char * const string); +CJSON_PUBLIC(cJSON_bool) cJSON_HasObjectItem(const cJSON *object, const char *string); +/* For analysing failed parses. This returns a pointer to the parse error. You'll probably need to look a few chars back to make sense of it. Defined when cJSON_Parse() returns 0. 0 when cJSON_Parse() succeeds. */ +CJSON_PUBLIC(const char *) cJSON_GetErrorPtr(void); + +/* Check if the item is a string and return its valuestring */ +CJSON_PUBLIC(char *) cJSON_GetStringValue(const cJSON * const item); + +/* These functions check the type of an item */ +CJSON_PUBLIC(cJSON_bool) cJSON_IsInvalid(const cJSON * const item); +CJSON_PUBLIC(cJSON_bool) cJSON_IsFalse(const cJSON * const item); +CJSON_PUBLIC(cJSON_bool) cJSON_IsTrue(const cJSON * const item); +CJSON_PUBLIC(cJSON_bool) cJSON_IsBool(const cJSON * const item); +CJSON_PUBLIC(cJSON_bool) cJSON_IsNull(const cJSON * const item); +CJSON_PUBLIC(cJSON_bool) cJSON_IsNumber(const cJSON * const item); +CJSON_PUBLIC(cJSON_bool) cJSON_IsString(const cJSON * const item); +CJSON_PUBLIC(cJSON_bool) cJSON_IsArray(const cJSON * const item); +CJSON_PUBLIC(cJSON_bool) cJSON_IsObject(const cJSON * const item); +CJSON_PUBLIC(cJSON_bool) cJSON_IsRaw(const cJSON * const item); + +/* These calls create a cJSON item of the appropriate type. */ +CJSON_PUBLIC(cJSON *) cJSON_CreateNull(void); +CJSON_PUBLIC(cJSON *) cJSON_CreateTrue(void); +CJSON_PUBLIC(cJSON *) cJSON_CreateFalse(void); +CJSON_PUBLIC(cJSON *) cJSON_CreateBool(cJSON_bool boolean); +CJSON_PUBLIC(cJSON *) cJSON_CreateNumber(double num); +CJSON_PUBLIC(cJSON *) cJSON_CreateString(const char *string); +/* raw json */ +CJSON_PUBLIC(cJSON *) cJSON_CreateRaw(const char *raw); +CJSON_PUBLIC(cJSON *) cJSON_CreateArray(void); +CJSON_PUBLIC(cJSON *) cJSON_CreateObject(void); + +/* Create a string where valuestring references a string so + * it will not be freed by cJSON_Delete */ +CJSON_PUBLIC(cJSON *) cJSON_CreateStringReference(const char *string); +/* Create an object/array that only references it's elements so + * they will not be freed by cJSON_Delete */ +CJSON_PUBLIC(cJSON *) cJSON_CreateObjectReference(const cJSON *child); +CJSON_PUBLIC(cJSON *) cJSON_CreateArrayReference(const cJSON *child); + +/* These utilities create an Array of count items. + * The parameter count cannot be greater than the number of elements in the number array, otherwise array access will be out of bounds.*/ +CJSON_PUBLIC(cJSON *) cJSON_CreateIntArray(const int *numbers, int count); +CJSON_PUBLIC(cJSON *) cJSON_CreateFloatArray(const float *numbers, int count); +CJSON_PUBLIC(cJSON *) cJSON_CreateDoubleArray(const double *numbers, int count); +CJSON_PUBLIC(cJSON *) cJSON_CreateStringArray(const char *const *strings, int count); + +/* Append item to the specified array/object. */ +CJSON_PUBLIC(void) cJSON_AddItemToArray(cJSON *array, cJSON *item); +CJSON_PUBLIC(void) cJSON_AddItemToObject(cJSON *object, const char *string, cJSON *item); +/* Use this when string is definitely const (i.e. a literal, or as good as), and will definitely survive the cJSON object. + * WARNING: When this function was used, make sure to always check that (item->type & cJSON_StringIsConst) is zero before + * writing to `item->string` */ +CJSON_PUBLIC(void) cJSON_AddItemToObjectCS(cJSON *object, const char *string, cJSON *item); +/* Append reference to item to the specified array/object. Use this when you want to add an existing cJSON to a new cJSON, but don't want to corrupt your existing cJSON. */ +CJSON_PUBLIC(void) cJSON_AddItemReferenceToArray(cJSON *array, cJSON *item); +CJSON_PUBLIC(void) cJSON_AddItemReferenceToObject(cJSON *object, const char *string, cJSON *item); + +/* Remove/Detach items from Arrays/Objects. */ +CJSON_PUBLIC(cJSON *) cJSON_DetachItemViaPointer(cJSON *parent, cJSON * const item); +CJSON_PUBLIC(cJSON *) cJSON_DetachItemFromArray(cJSON *array, int which); +CJSON_PUBLIC(void) cJSON_DeleteItemFromArray(cJSON *array, int which); +CJSON_PUBLIC(cJSON *) cJSON_DetachItemFromObject(cJSON *object, const char *string); +CJSON_PUBLIC(cJSON *) cJSON_DetachItemFromObjectCaseSensitive(cJSON *object, const char *string); +CJSON_PUBLIC(void) cJSON_DeleteItemFromObject(cJSON *object, const char *string); +CJSON_PUBLIC(void) cJSON_DeleteItemFromObjectCaseSensitive(cJSON *object, const char *string); + +/* Update array items. */ +CJSON_PUBLIC(void) cJSON_InsertItemInArray(cJSON *array, int which, cJSON *newitem); /* Shifts pre-existing items to the right. */ +CJSON_PUBLIC(cJSON_bool) cJSON_ReplaceItemViaPointer(cJSON * const parent, cJSON * const item, cJSON * replacement); +CJSON_PUBLIC(void) cJSON_ReplaceItemInArray(cJSON *array, int which, cJSON *newitem); +CJSON_PUBLIC(void) cJSON_ReplaceItemInObject(cJSON *object,const char *string,cJSON *newitem); +CJSON_PUBLIC(void) cJSON_ReplaceItemInObjectCaseSensitive(cJSON *object,const char *string,cJSON *newitem); + +/* Duplicate a cJSON item */ +CJSON_PUBLIC(cJSON *) cJSON_Duplicate(const cJSON *item, cJSON_bool recurse); +/* Duplicate will create a new, identical cJSON item to the one you pass, in new memory that will + * need to be released. With recurse!=0, it will duplicate any children connected to the item. + * The item->next and ->prev pointers are always zero on return from Duplicate. */ +/* Recursively compare two cJSON items for equality. If either a or b is NULL or invalid, they will be considered unequal. + * case_sensitive determines if object keys are treated case sensitive (1) or case insensitive (0) */ +CJSON_PUBLIC(cJSON_bool) cJSON_Compare(const cJSON * const a, const cJSON * const b, const cJSON_bool case_sensitive); + +/* Minify a strings, remove blank characters(such as ' ', '\t', '\r', '\n') from strings. + * The input pointer json cannot point to a read-only address area, such as a string constant, + * but should point to a readable and writable adress area. */ +CJSON_PUBLIC(void) cJSON_Minify(char *json); + +/* Helper functions for creating and adding items to an object at the same time. + * They return the added item or NULL on failure. */ +CJSON_PUBLIC(cJSON*) cJSON_AddNullToObject(cJSON * const object, const char * const name); +CJSON_PUBLIC(cJSON*) cJSON_AddTrueToObject(cJSON * const object, const char * const name); +CJSON_PUBLIC(cJSON*) cJSON_AddFalseToObject(cJSON * const object, const char * const name); +CJSON_PUBLIC(cJSON*) cJSON_AddBoolToObject(cJSON * const object, const char * const name, const cJSON_bool boolean); +CJSON_PUBLIC(cJSON*) cJSON_AddNumberToObject(cJSON * const object, const char * const name, const double number); +CJSON_PUBLIC(cJSON*) cJSON_AddStringToObject(cJSON * const object, const char * const name, const char * const string); +CJSON_PUBLIC(cJSON*) cJSON_AddRawToObject(cJSON * const object, const char * const name, const char * const raw); +CJSON_PUBLIC(cJSON*) cJSON_AddObjectToObject(cJSON * const object, const char * const name); +CJSON_PUBLIC(cJSON*) cJSON_AddArrayToObject(cJSON * const object, const char * const name); + +/* When assigning an integer value, it needs to be propagated to valuedouble too. */ +#define cJSON_SetIntValue(object, number) ((object) ? (object)->valueint = (object)->valuedouble = (number) : (number)) +/* helper for the cJSON_SetNumberValue macro */ +CJSON_PUBLIC(double) cJSON_SetNumberHelper(cJSON *object, double number); +#define cJSON_SetNumberValue(object, number) ((object != NULL) ? cJSON_SetNumberHelper(object, (double)number) : (number)) + +/* Macro for iterating over an array or object */ +#define cJSON_ArrayForEach(element, array) for(element = (array != NULL) ? (array)->child : NULL; element != NULL; element = element->next) + +/* malloc/free objects using the malloc/free functions that have been set with cJSON_InitHooks */ +CJSON_PUBLIC(void *) cJSON_malloc(size_t size); +CJSON_PUBLIC(void) cJSON_free(void *object); + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/tool/libclang_config.yaml b/tool/libclang_config.yaml new file mode 100644 index 00000000..575a4400 --- /dev/null +++ b/tool/libclang_config.yaml @@ -0,0 +1,76 @@ +# Copyright (c) 2020, the Dart project authors. Please see the AUTHORS file +# for details. All rights reserved. Use of this source code is governed by a +# BSD-style license that can be found in the LICENSE file. + +# Config file for generating the libclang bindings used by this package. + +# ===================== GENERATING BINDINGS ===================== +# cd to `tool`, and run - +# dart ../bin/generate.dart --config libclang_config.yaml +# =============================================================== + +output: '../lib/src/header_parser/clang_bindings/clang_bindings.dart' +libclang-dylib-folder: 'wrapped_libclang' +sort: true +compiler-opts: '-I/usr/lib/llvm-9/include/ -I/usr/lib/llvm-10/include/ -I/usr/local/opt/llvm/include/ -I/Applications/Xcode.app/Contents/Developer/Platforms/MacOSX.platform/Developer/SDKs/MacOSX.sdk/usr/include/' +headers: + - 'wrapped_libclang/wrapper.c' +header-filter: + include: + - wrapper.c + - Index.h + - CXString.h + +enums: + include: + names: + - CXChildVisitResult + - CXCursorKind + - CXTypeKind + - CXDiagnosticDisplayOptions + - CXTranslationUnit_Flags + +structs: + include: + names: + - CXCursor + - CXType + +functions: + include: + names: + - clang_createIndex + - clang_disposeIndex + - clang_getNumDiagnostics + - clang_getDiagnostic + - clang_disposeDiagnostic + - clang_parseTranslationUnit + - clang_disposeTranslationUnit + - clang_getCString_wrap + - clang_disposeString_wrap + - clang_getCursorKind_wrap + - clang_getCursorKindSpelling_wrap + - clang_getCursorType_wrap + - clang_getTypeSpelling_wrap + - clang_getTypeKindSpelling_wrap + - clang_getResultType_wrap + - clang_getPointeeType_wrap + - clang_getCanonicalType_wrap + - clang_Type_getNamedType_wrap + - clang_getTypeDeclaration_wrap + - clang_getTypedefDeclUnderlyingType_wrap + - clang_getCursorSpelling_wrap + - clang_getTranslationUnitCursor_wrap + - clang_formatDiagnostic_wrap + - clang_visitChildren_wrap + - clang_Cursor_getNumArguments_wrap + - clang_Cursor_getArgument_wrap + - clang_getNumArgTypes_wrap + - clang_getArgType_wrap + - clang_getEnumConstantDeclValue_wrap + - clang_Cursor_getBriefCommentText_wrap + - clang_getCursorLocation_wrap + - clang_getFileLocation_wrap + - clang_getFileName_wrap + - clang_getNumElements_wrap + - clang_getArrayElementType_wrap diff --git a/tool/wrapped_libclang/.gitignore b/tool/wrapped_libclang/.gitignore new file mode 100644 index 00000000..2b64ac7f --- /dev/null +++ b/tool/wrapped_libclang/.gitignore @@ -0,0 +1,12 @@ +# general gitignore for CMake. +CMakeLists.txt.user +CMakeCache.txt +CMakeFiles +CMakeScripts +Testing +Makefile +cmake_install.cmake +install_manifest.txt +compile_commands.json +CTestTestfile.cmake +_deps diff --git a/tool/wrapped_libclang/build.dart b/tool/wrapped_libclang/build.dart new file mode 100644 index 00000000..20971b1d --- /dev/null +++ b/tool/wrapped_libclang/build.dart @@ -0,0 +1,216 @@ +// Copyright (c) 2020, the Dart project authors. Please see the AUTHORS file +// for details. All rights reserved. Use of this source code is governed by a +// BSD-style license that can be found in the LICENSE file. + +/// ======================================================================= +/// =============== Build script to generate dyamic library =============== +/// ======================================================================= +/// This Script effectively calls the following (but user can provide +/// command line args which will replace the defaults shown below)- +/// +/// Linux: +/// ``` +/// clang -I/usr/lib/llvm-9/include/ -I/usr/lib/llvm-10/include/ -lclang -shared -fpic wrapper.c -o libwrapped_clang.so +/// ``` +/// MacOS: +/// ``` +/// clang -I/usr/local/opt/llvm/include/ -L/usr/local/opt/llvm/lib/ -I/Applications/Xcode.app/Contents/Developer/Platforms/MacOSX.platform/Developer/SDKs/MacOSX.sdk/usr/include/ -v -lclang -shared -fpic wrapper.c -o libwrapped_clang.dylib +/// ``` +/// Windows: +/// ``` +/// clang -IC:\Progra~1\LLVM\include -LC:\Progra~1\LLVM\lib -llibclang -shared wrapper.c -o wrapped_clang.dll -Wl,/DEF:wrapper.def +/// del wrapped_clang.exp +/// del wrapped_clang.lib +/// ``` +/// ======================================================================= +/// ======================================================================= +/// ======================================================================= + +import 'dart:io'; +import 'package:args/args.dart'; +import 'package:meta/meta.dart'; + +const MACOS = 'macos'; +const WINDOWS = 'windows'; +const LINUX = 'linux'; + +/// Default platform options. +Map platformOptions = { + LINUX: Options( + outputfilename: 'libwrapped_clang.so', + sharedFlag: '-shared', + inputHeader: 'wrapper.c', + fPIC: '-fpic', + ldLibFlag: '-lclang', + headerIncludes: [ + '-I/usr/lib/llvm-9/include/', + '-I/usr/lib/llvm-10/include/', + ], + ), + WINDOWS: Options( + outputfilename: 'wrapped_clang.dll', + sharedFlag: '-shared', + inputHeader: 'wrapper.c', + moduleDefPath: '-Wl,/DEF:wrapper.def', + ldLibFlag: '-llibclang', + headerIncludes: [ + r'-IC:\Progra~1\LLVM\include', + ], + libIncludes: [ + r'-LC:\Progra~1\LLVM\lib', + ], + ), + MACOS: Options( + outputfilename: 'libwrapped_clang.dylib', + sharedFlag: '-shared', + inputHeader: 'wrapper.c', + fPIC: '-fpic', + ldLibFlag: '-lclang', + headerIncludes: [ + '-I/usr/local/opt/llvm/include/', + '-I/Applications/Xcode.app/Contents/Developer/Platforms/MacOSX.platform/Developer/SDKs/MacOSX.sdk/usr/include/', + ], + libIncludes: [ + '-L/usr/local/opt/llvm/lib/', + ], + ), +}; + +void main(List arguments) { + print('Building Dynamic Library for libclang wrapper... '); + final options = getPlatformOptions(); + + // Updates header/lib includes in platform options. + changeIncludesUsingCmdArgs(arguments, options); + + // Run clang compiler to generate the dynamic library. + final ProcessResult result = runClangProcess(options); + printSuccess(result, options); +} + +/// Calls the clang compiler. +ProcessResult runClangProcess(Options options) { + final result = Process.runSync( + 'clang', + [ + ...options.headerIncludes, + ...options.libIncludes, + options.ldLibFlag, + options.sharedFlag, + options.fPIC, + options.inputHeader, + '-o', + options.outputfilename, + options.moduleDefPath, + ], + ); + return result; +} + +/// Prints success message (or process error if any). +void printSuccess(ProcessResult result, Options options) { + print(result.stdout); + if ((result.stderr as String).isEmpty) { + print('Generated file: ${options.outputfilename}'); + } else { + print(result.stderr); + } +} + +ArgResults getArgResults(List args) { + final parser = ArgParser(allowTrailingOptions: true); + parser.addSeparator( + 'Build Script to generate dynamic library used by this package:'); + parser.addMultiOption('include-header', + abbr: 'I', help: 'Path to header include directories'); + parser.addMultiOption('include-lib', + abbr: 'L', help: 'Path to library include directories'); + parser.addFlag( + 'help', + abbr: 'h', + help: 'prints this usage', + negatable: false, + ); + + ArgResults results; + try { + results = parser.parse(args); + + if (results.wasParsed('help')) { + print(parser.usage); + exit(0); + } + } catch (e) { + print(e); + print(parser.usage); + exit(1); + } + + return results; +} + +/// Use cmd args(if any) to change header/lib include paths. +void changeIncludesUsingCmdArgs(List arguments, Options options) { + final argResult = getArgResults(arguments); + if (argResult.wasParsed('include-header')) { + options.headerIncludes = (argResult['include-header'] as List) + .map((header) => '-I$header') + .toList(); + } + if (argResult.wasParsed('include-lib')) { + options.libIncludes = (argResult['include-lib'] as List) + .map((lib) => '-L$lib') + .toList(); + } +} + +/// Get options based on current platform. +Options getPlatformOptions() { + if (Platform.isMacOS) { + return platformOptions[MACOS]; + } else if (Platform.isWindows) { + return platformOptions[WINDOWS]; + } else if (Platform.isLinux) { + return platformOptions[LINUX]; + } else { + throw Exception('Unknown Platform.'); + } +} + +/// Hold options which would be passed to clang. +class Options { + /// Name of dynamic library to generate. + final String outputfilename; + + /// Tells compiler to generate a shared library. + final String sharedFlag; + + /// Flag for generating Position Independant Code (Not used on windows). + final String fPIC; + + /// Input file. + final String inputHeader; + + /// Path to `.def` file containing symbols to export, windows use only. + final String moduleDefPath; + + /// Path to header files. + List headerIncludes; + + /// Path to dynamic/static libraries + List libIncludes; + + /// Linker flag for linking to libclang. + final String ldLibFlag; + + Options({ + @required this.outputfilename, + @required this.sharedFlag, + @required this.inputHeader, + @required this.ldLibFlag, + this.headerIncludes = const [], + this.libIncludes = const [], + this.fPIC = '', + this.moduleDefPath = '', + }); +} diff --git a/tool/wrapped_libclang/wrapper.c b/tool/wrapped_libclang/wrapper.c new file mode 100644 index 00000000..2e0e375c --- /dev/null +++ b/tool/wrapped_libclang/wrapper.c @@ -0,0 +1,274 @@ +// Copyright (c) 2020, the Dart project authors. Please see the AUTHORS file +// for details. All rights reserved. Use of this source code is governed by a +// BSD-style license that can be found in the LICENSE file. + +#include +#include +#include + +// utility. +#define aloc(T) ((T *)malloc(sizeof(T))) +CXCursor *ptrToCXCursor(CXCursor t) +{ + CXCursor *c = aloc(CXCursor); + *c = t; + return c; +} +CXString *ptrToCXString(CXString t) +{ + CXString *c = aloc(CXString); + *c = t; + return c; +} +CXType *ptrToCXType(CXType t) +{ + CXType *c = aloc(CXType); + *c = t; + return c; +} +CXSourceLocation *ptrToCXSourceLocation(CXSourceLocation t) +{ + CXSourceLocation *c = aloc(CXSourceLocation); + *c = t; + return c; +} +// START ===== Functions for testing libclang behavior in C. +enum CXChildVisitResult visitor_for_test_in_c(CXCursor cursor, CXCursor parent, CXClientData clientData) +{ + printf("Cursor- kind: %s, name: %s\n", clang_getCString(clang_getCursorKindSpelling(clang_getCursorKind(cursor))), clang_getCString(clang_getCursorSpelling(cursor))); + return CXChildVisit_Continue; +} +int test_in_c() +{ + printf("==========================run==========================\n"); + CXIndex Index = clang_createIndex(0, 0); + CXTranslationUnit TU = clang_parseTranslationUnit(Index, + "./test.h", 0, 0, NULL, 0, CXTranslationUnit_None); + + if (TU == NULL) + { + printf("Error creating TU\n"); + return 0; + } + + CXCursor root = clang_getTranslationUnitCursor(TU); + + unsigned a = clang_visitChildren(root, visitor_for_test_in_c, NULL); + + clang_disposeTranslationUnit(TU); + clang_disposeIndex(Index); + printf("\n==========================end==========================\n"); + return 0; +} +// END ===== Functions for testing libclang behavior in C ============================ + +// START ===== WRAPPER FUNCTIONS ===================== + +const char *clang_getCString_wrap(CXString *string) +{ + const char *a = clang_getCString(*string); + + return a; +} + +void clang_disposeString_wrap(CXString *string) +{ + clang_disposeString(*string); + free(string); + return; +} + +enum CXCursorKind clang_getCursorKind_wrap(CXCursor *cursor) +{ + return clang_getCursorKind(*cursor); +} + +CXString *clang_getCursorKindSpelling_wrap(enum CXCursorKind kind) +{ + return ptrToCXString(clang_getCursorKindSpelling(kind)); +} + +CXType *clang_getCursorType_wrap(CXCursor *cursor) +{ + return ptrToCXType(clang_getCursorType(*cursor)); +} + +CXString *clang_getTypeSpelling_wrap(CXType *type) +{ + return ptrToCXString(clang_getTypeSpelling(*type)); +} + +CXString *clang_getTypeKindSpelling_wrap(enum CXTypeKind typeKind) +{ + return ptrToCXString(clang_getTypeKindSpelling(typeKind)); +} + +CXType *clang_getResultType_wrap(CXType *functionType) +{ + return ptrToCXType(clang_getResultType(*functionType)); +} + +CXType *clang_getPointeeType_wrap(CXType *pointerType) +{ + return ptrToCXType(clang_getPointeeType(*pointerType)); +} + +CXType *clang_getCanonicalType_wrap(CXType *typerefType) +{ + return ptrToCXType(clang_getCanonicalType(*typerefType)); +} + +CXType *clang_Type_getNamedType_wrap(CXType *elaboratedType) +{ + return ptrToCXType(clang_Type_getNamedType(*elaboratedType)); +} + +CXCursor *clang_getTypeDeclaration_wrap(CXType *cxtype) +{ + return ptrToCXCursor(clang_getTypeDeclaration(*cxtype)); +} + +CXType *clang_getTypedefDeclUnderlyingType_wrap(CXCursor *cxcursor) +{ + return ptrToCXType(clang_getTypedefDeclUnderlyingType(*cxcursor)); +} + +/** The name of parameter, struct, typedef. */ +CXString *clang_getCursorSpelling_wrap(CXCursor *cursor) +{ + return ptrToCXString(clang_getCursorSpelling(*cursor)); +} + +CXCursor *clang_getTranslationUnitCursor_wrap(CXTranslationUnit tu) +{ + return ptrToCXCursor(clang_getTranslationUnitCursor(tu)); +} + +CXString *clang_formatDiagnostic_wrap(CXDiagnostic diag, int opts) +{ + return ptrToCXString(clang_formatDiagnostic(diag, opts)); +} + +// alternative typedef for [CXCursorVisitor] using pointer for passing cursor and parent +// instead of passing by value +typedef enum CXChildVisitResult (*ModifiedCXCursorVisitor)(CXCursor *cursor, + CXCursor *parent, + CXClientData client_data); + +// holds Pointers to Dart function received from [clang_visitChildren_wrap] +// called in [_visitorWrap] +struct _stackForVisitChildren +{ + ModifiedCXCursorVisitor modifiedVisitor; + struct _stackForVisitChildren *link; +} * _visitorTop, *_visitorTemp; +void _push(ModifiedCXCursorVisitor modifiedVisitor) +{ + if (_visitorTop == NULL) + { + _visitorTop = (struct _stackForVisitChildren *)malloc(1 * sizeof(struct _stackForVisitChildren)); + _visitorTop->link = NULL; + _visitorTop->modifiedVisitor = modifiedVisitor; + } + else + { + _visitorTemp = (struct _stackForVisitChildren *)malloc(1 * sizeof(struct _stackForVisitChildren)); + _visitorTemp->link = _visitorTop; + _visitorTemp->modifiedVisitor = modifiedVisitor; + _visitorTop = _visitorTemp; + } +} +void _pop() +{ + _visitorTemp = _visitorTop; + + if (_visitorTemp == NULL) + { + printf("\n Error, Wrapper.C : Trying to pop from empty stack"); + return; + } + else + _visitorTemp = _visitorTop->link; + free(_visitorTop); + _visitorTop = _visitorTemp; +} +ModifiedCXCursorVisitor _top() +{ + return _visitorTop->modifiedVisitor; +} +// Do not write binding for this function. +// used by [clang_visitChildren_wrap]. +enum CXChildVisitResult +_visitorwrap(CXCursor cursor, CXCursor parent, CXClientData clientData) +{ + enum CXChildVisitResult e = (_top()(ptrToCXCursor(cursor), ptrToCXCursor(parent), clientData)); + return e; +} + +/** Visitor is a function pointer with parameters having pointers to cxcursor +* instead of cxcursor by default. */ +unsigned clang_visitChildren_wrap(CXCursor *parent, ModifiedCXCursorVisitor _modifiedVisitor, CXClientData clientData) +{ + _push(_modifiedVisitor); + unsigned a = clang_visitChildren(*parent, _visitorwrap, clientData); + _pop(); + return a; +} + +int clang_Cursor_getNumArguments_wrap(CXCursor *cursor) +{ + return clang_Cursor_getNumArguments(*cursor); +} + +CXCursor *clang_Cursor_getArgument_wrap(CXCursor *cursor, unsigned i) +{ + return ptrToCXCursor(clang_Cursor_getArgument(*cursor, i)); +} + +int clang_getNumArgTypes_wrap(CXType *cxtype) +{ + return clang_getNumArgTypes(*cxtype); +} + +CXType *clang_getArgType_wrap(CXType *cxtype, unsigned i) +{ + return ptrToCXType(clang_getArgType(*cxtype, i)); +} + +long long clang_getEnumConstantDeclValue_wrap(CXCursor *cursor) +{ + return clang_getEnumConstantDeclValue(*cursor); +} + +/** Returns the first paragraph of doxygen doc comment. */ +CXString *clang_Cursor_getBriefCommentText_wrap(CXCursor *cursor) +{ + return ptrToCXString(clang_Cursor_getBriefCommentText(*cursor)); +} + +CXSourceLocation *clang_getCursorLocation_wrap(CXCursor *cursor) +{ + return ptrToCXSourceLocation(clang_getCursorLocation(*cursor)); +} + +void clang_getFileLocation_wrap(CXSourceLocation *location, CXFile *file, unsigned *line, unsigned *column, unsigned *offset) +{ + return clang_getFileLocation(*location, file, line, column, offset); +} + +CXString *clang_getFileName_wrap(CXFile SFile) +{ + return ptrToCXString(clang_getFileName(SFile)); +} + +unsigned long long clang_getNumElements_wrap(CXType *cxtype) +{ + return clang_getNumElements(*cxtype); +} + +CXType *clang_getArrayElementType_wrap(CXType *cxtype) +{ + return ptrToCXType(clang_getArrayElementType(*cxtype)); +} + +// END ===== WRAPPER FUNCTIONS ===================== diff --git a/tool/wrapped_libclang/wrapper.def b/tool/wrapped_libclang/wrapper.def new file mode 100644 index 00000000..36902ae7 --- /dev/null +++ b/tool/wrapped_libclang/wrapper.def @@ -0,0 +1,352 @@ +; Copyright (c) 2020, the Dart project authors. Please see the AUTHORS file +; for details. All rights reserved. Use of this source code is governed by a +; BSD-style license that can be found in the LICENSE file. + +EXPORTS +clang_getCString +clang_disposeString +clang_disposeStringSet +clang_createIndex +clang_disposeIndex +clang_CXIndex_setGlobalOptions +clang_CXIndex_getGlobalOptions +clang_CXIndex_setInvocationEmissionPathOption +clang_getFileName +clang_getFileTime +clang_getFileUniqueID +clang_isFileMultipleIncludeGuarded +clang_getFile +clang_getFileContents +clang_File_isEqual +clang_File_tryGetRealPathName +clang_getNullLocation +clang_equalLocations +clang_getLocation +clang_getLocationForOffset +clang_Location_isInSystemHeader +clang_Location_isFromMainFile +clang_getNullRange +clang_getRange +clang_equalRanges +clang_Range_isNull +clang_getExpansionLocation +clang_getPresumedLocation +clang_getInstantiationLocation +clang_getSpellingLocation +clang_getFileLocation +clang_getRangeStart +clang_getRangeEnd +clang_getSkippedRanges +clang_getAllSkippedRanges +clang_disposeSourceRangeList +clang_getNumDiagnosticsInSet +clang_getDiagnosticInSet +clang_loadDiagnostics +clang_disposeDiagnosticSet +clang_getChildDiagnostics +clang_getNumDiagnostics +clang_getDiagnostic +clang_getDiagnosticSetFromTU +clang_disposeDiagnostic +clang_formatDiagnostic +clang_defaultDiagnosticDisplayOptions +clang_getDiagnosticSeverity +clang_getDiagnosticLocation +clang_getDiagnosticSpelling +clang_getDiagnosticOption +clang_getDiagnosticCategory +clang_getDiagnosticCategoryName +clang_getDiagnosticCategoryText +clang_getDiagnosticNumRanges +clang_getDiagnosticRange +clang_getDiagnosticNumFixIts +clang_getDiagnosticFixIt +clang_getTranslationUnitSpelling +clang_createTranslationUnitFromSourceFile +clang_createTranslationUnit +clang_createTranslationUnit2 +clang_defaultEditingTranslationUnitOptions +clang_parseTranslationUnit +clang_parseTranslationUnit2 +clang_parseTranslationUnit2FullArgv +clang_defaultSaveOptions +clang_saveTranslationUnit +clang_suspendTranslationUnit +clang_disposeTranslationUnit +clang_defaultReparseOptions +clang_reparseTranslationUnit +clang_getTUResourceUsageName +clang_getCXTUResourceUsage +clang_disposeCXTUResourceUsage +clang_getTranslationUnitTargetInfo +clang_TargetInfo_dispose +clang_TargetInfo_getTriple +clang_TargetInfo_getPointerWidth +clang_getNullCursor +clang_getTranslationUnitCursor +clang_equalCursors +clang_Cursor_isNull +clang_hashCursor +clang_getCursorKind +clang_isDeclaration +clang_isInvalidDeclaration +clang_isReference +clang_isExpression +clang_isStatement +clang_isAttribute +clang_Cursor_hasAttrs +clang_isInvalid +clang_isTranslationUnit +clang_isPreprocessing +clang_isUnexposed +clang_getCursorLinkage +clang_getCursorVisibility +clang_getCursorAvailability +clang_getCursorPlatformAvailability +clang_disposeCXPlatformAvailability +clang_getCursorLanguage +clang_getCursorTLSKind +clang_Cursor_getTranslationUnit +clang_createCXCursorSet +clang_disposeCXCursorSet +clang_CXCursorSet_contains +clang_CXCursorSet_insert +clang_getCursorSemanticParent +clang_getCursorLexicalParent +clang_getOverriddenCursors +clang_disposeOverriddenCursors +clang_getIncludedFile +clang_getCursor +clang_getCursorLocation +clang_getCursorExtent +clang_getCursorType +clang_getTypeSpelling +clang_getTypedefDeclUnderlyingType +clang_getEnumDeclIntegerType +clang_getEnumConstantDeclValue +clang_getEnumConstantDeclUnsignedValue +clang_getFieldDeclBitWidth +clang_Cursor_getNumArguments +clang_Cursor_getArgument +clang_Cursor_getNumTemplateArguments +clang_Cursor_getTemplateArgumentKind +clang_Cursor_getTemplateArgumentType +clang_Cursor_getTemplateArgumentValue +clang_Cursor_getTemplateArgumentUnsignedValue +clang_equalTypes +clang_getCanonicalType +clang_isConstQualifiedType +clang_Cursor_isMacroFunctionLike +clang_Cursor_isMacroBuiltin +clang_Cursor_isFunctionInlined +clang_isVolatileQualifiedType +clang_isRestrictQualifiedType +clang_getAddressSpace +clang_getTypedefName +clang_getPointeeType +clang_getTypeDeclaration +clang_getDeclObjCTypeEncoding +clang_Type_getObjCEncoding +clang_getTypeKindSpelling +clang_getFunctionTypeCallingConv +clang_getResultType +clang_getExceptionSpecificationType +clang_getNumArgTypes +clang_getArgType +clang_Type_getObjCObjectBaseType +clang_Type_getNumObjCProtocolRefs +clang_Type_getObjCProtocolDecl +clang_Type_getNumObjCTypeArgs +clang_Type_getObjCTypeArg +clang_isFunctionTypeVariadic +clang_getCursorResultType +clang_getCursorExceptionSpecificationType +clang_isPODType +clang_getElementType +clang_getNumElements +clang_getArrayElementType +clang_getArraySize +clang_Type_getNamedType +clang_Type_isTransparentTagTypedef +clang_Type_getNullability +clang_Type_getAlignOf +clang_Type_getClassType +clang_Type_getSizeOf +clang_Type_getOffsetOf +clang_Type_getModifiedType +clang_Cursor_getOffsetOfField +clang_Cursor_isAnonymous +clang_Cursor_isAnonymousRecordDecl +clang_Cursor_isInlineNamespace +clang_Type_getNumTemplateArguments +clang_Type_getTemplateArgumentAsType +clang_Type_getCXXRefQualifier +clang_Cursor_isBitField +clang_isVirtualBase +clang_getCXXAccessSpecifier +clang_Cursor_getStorageClass +clang_getNumOverloadedDecls +clang_getOverloadedDecl +clang_getIBOutletCollectionType +clang_visitChildren +clang_getCursorUSR +clang_constructUSR_ObjCClass +clang_constructUSR_ObjCCategory +clang_constructUSR_ObjCProtocol +clang_constructUSR_ObjCIvar +clang_constructUSR_ObjCMethod +clang_constructUSR_ObjCProperty +clang_getCursorSpelling +clang_Cursor_getSpellingNameRange +clang_PrintingPolicy_getProperty +clang_PrintingPolicy_setProperty +clang_getCursorPrintingPolicy +clang_PrintingPolicy_dispose +clang_getCursorPrettyPrinted +clang_getCursorDisplayName +clang_getCursorReferenced +clang_getCursorDefinition +clang_isCursorDefinition +clang_getCanonicalCursor +clang_Cursor_getObjCSelectorIndex +clang_Cursor_isDynamicCall +clang_Cursor_getReceiverType +clang_Cursor_getObjCPropertyAttributes +clang_Cursor_getObjCPropertyGetterName +clang_Cursor_getObjCPropertySetterName +clang_Cursor_getObjCDeclQualifiers +clang_Cursor_isObjCOptional +clang_Cursor_isVariadic +clang_Cursor_isExternalSymbol +clang_Cursor_getCommentRange +clang_Cursor_getRawCommentText +clang_Cursor_getBriefCommentText +clang_Cursor_getMangling +clang_Cursor_getCXXManglings +clang_Cursor_getObjCManglings +clang_Cursor_getModule +clang_getModuleForFile +clang_Module_getASTFile +clang_Module_getParent +clang_Module_getName +clang_Module_getFullName +clang_Module_isSystem +clang_Module_getNumTopLevelHeaders +clang_Module_getTopLevelHeader +clang_CXXConstructor_isConvertingConstructor +clang_CXXConstructor_isCopyConstructor +clang_CXXConstructor_isDefaultConstructor +clang_CXXConstructor_isMoveConstructor +clang_CXXField_isMutable +clang_CXXMethod_isDefaulted +clang_CXXMethod_isPureVirtual +clang_CXXMethod_isStatic +clang_CXXMethod_isVirtual +clang_CXXRecord_isAbstract +clang_EnumDecl_isScoped +clang_CXXMethod_isConst +clang_getTemplateCursorKind +clang_getSpecializedCursorTemplate +clang_getCursorReferenceNameRange +clang_getToken +clang_getTokenKind +clang_getTokenSpelling +clang_getTokenLocation +clang_getTokenExtent +clang_tokenize +clang_annotateTokens +clang_disposeTokens +clang_getCursorKindSpelling +clang_getDefinitionSpellingAndExtent +clang_enableStackTraces +clang_executeOnThread +clang_getCompletionChunkKind +clang_getCompletionChunkText +clang_getCompletionChunkCompletionString +clang_getNumCompletionChunks +clang_getCompletionPriority +clang_getCompletionAvailability +clang_getCompletionNumAnnotations +clang_getCompletionAnnotation +clang_getCompletionParent +clang_getCompletionBriefComment +clang_getCursorCompletionString +clang_getCompletionNumFixIts +clang_getCompletionFixIt +clang_defaultCodeCompleteOptions +clang_codeCompleteAt +clang_sortCodeCompletionResults +clang_disposeCodeCompleteResults +clang_codeCompleteGetNumDiagnostics +clang_codeCompleteGetDiagnostic +clang_codeCompleteGetContexts +clang_codeCompleteGetContainerKind +clang_codeCompleteGetContainerUSR +clang_codeCompleteGetObjCSelector +clang_getClangVersion +clang_toggleCrashRecovery +clang_getInclusions +clang_Cursor_Evaluate +clang_EvalResult_getKind +clang_EvalResult_getAsInt +clang_EvalResult_getAsLongLong +clang_EvalResult_isUnsignedInt +clang_EvalResult_getAsUnsigned +clang_EvalResult_getAsDouble +clang_EvalResult_getAsStr +clang_EvalResult_dispose +clang_getRemappings +clang_getRemappingsFromFileList +clang_remap_getNumFiles +clang_remap_getFilenames +clang_remap_dispose +clang_findReferencesInFile +clang_findIncludesInFile +clang_index_isEntityObjCContainerKind +clang_index_getObjCContainerDeclInfo +clang_index_getObjCInterfaceDeclInfo +clang_index_getObjCCategoryDeclInfo +clang_index_getObjCProtocolRefListInfo +clang_index_getObjCPropertyDeclInfo +clang_index_getIBOutletCollectionAttrInfo +clang_index_getCXXClassDeclInfo +clang_index_getClientContainer +clang_index_setClientContainer +clang_index_getClientEntity +clang_index_setClientEntity +clang_IndexAction_create +clang_IndexAction_dispose +clang_indexSourceFile +clang_indexSourceFileFullArgv +clang_indexTranslationUnit +clang_indexLoc_getFileLocation +clang_indexLoc_getCXSourceLocation +clang_Type_visitFields +clang_getCString_wrap +clang_disposeString_wrap +clang_getCursorKind_wrap +clang_getCursorKindSpelling_wrap +clang_getCursorType_wrap +clang_getTypeSpelling_wrap +clang_getTypeKindSpelling_wrap +clang_getResultType_wrap +clang_getPointeeType_wrap +clang_getCanonicalType_wrap +clang_Type_getNamedType_wrap +clang_getTypeDeclaration_wrap +clang_getTypedefDeclUnderlyingType_wrap +clang_getCursorSpelling_wrap +clang_getTranslationUnitCursor_wrap +clang_formatDiagnostic_wrap +clang_visitChildren_wrap +clang_Cursor_getNumArguments_wrap +clang_Cursor_getArgument_wrap +clang_getNumArgTypes_wrap +clang_getArgType_wrap +clang_getEnumConstantDeclValue_wrap +clang_Cursor_getBriefCommentText_wrap +clang_getCursorLocation_wrap +clang_getFileLocation_wrap +clang_getFileName_wrap +clang_getNumElements_wrap +clang_getArrayElementType_wrap