[ffigen] Added support for Global variables (#139) (#165)

diff --git a/pkgs/ffigen/CHANGELOG.md b/pkgs/ffigen/CHANGELOG.md
index a7b8617..1e49bdc 100644
--- a/pkgs/ffigen/CHANGELOG.md
+++ b/pkgs/ffigen/CHANGELOG.md
@@ -1,3 +1,6 @@
+# 2.0.0-dev.4
+- Add support for parsing and generating globals.
+
 # 2.0.0-dev.3
 - Removed the usage of `--no-sound-null-safety` flag.
 
diff --git a/pkgs/ffigen/README.md b/pkgs/ffigen/README.md
index df041e7..f2c194e 100644
--- a/pkgs/ffigen/README.md
+++ b/pkgs/ffigen/README.md
@@ -144,7 +144,7 @@
   </td>
   </tr>
   <tr>
-    <td>functions<br>structs<br>enums<br>unnamed-enums<br>macros</td>
+    <td>functions<br>structs<br>enums<br>unnamed-enums<br>macros<br>globals</td>
     <td>Filters for declarations.<br><b>Default: all are included</b></td>
     <td>
 
@@ -170,6 +170,12 @@
     'CXTypeKind': # Full names have higher priority.
       # $1 keeps only the 1st group i.e '(.*)'.
       'CXType(.*)': '$1'
+globals:
+  exclude:
+    - aGlobal
+  rename:
+    # Removes '_' from beginning of a name.
+    - '_(.*)': '$1'
 ```
   </td>
   </tr>
diff --git a/pkgs/ffigen/lib/src/code_generator/global.dart b/pkgs/ffigen/lib/src/code_generator/global.dart
index b52fa70..d419e92 100644
--- a/pkgs/ffigen/lib/src/code_generator/global.dart
+++ b/pkgs/ffigen/lib/src/code_generator/global.dart
@@ -2,6 +2,8 @@
 // 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/code_generator/typedef.dart';
+
 import 'binding.dart';
 import 'binding_string.dart';
 import 'type.dart';
@@ -34,6 +36,21 @@
           dartDoc: dartDoc,
         );
 
+  List<Typedef>? _typedefDependencies;
+  @override
+  List<Typedef> getTypedefDependencies(Writer w) {
+    if (_typedefDependencies == null) {
+      _typedefDependencies = <Typedef>[];
+
+      // Add typedef's required by the variable's type.
+      final valueType = type.getBaseType();
+      if (valueType.broadType == BroadType.NativeFunction) {
+        _typedefDependencies!.addAll(valueType.nativeFunc!.getDependencies());
+      }
+    }
+    return _typedefDependencies!;
+  }
+
   @override
   BindingString toBindingString(Writer w) {
     final s = StringBuffer();
@@ -41,13 +58,18 @@
     if (dartDoc != null) {
       s.write(makeDartDoc(dartDoc!));
     }
+    final pointerName = w.wrapperLevelUniqueNamer.makeUnique('_$globalVarName');
+    final dartType = type.getDartType(w);
+    final cType = type.getCType(w);
+    final refOrValue = type.broadType == BroadType.Struct ? 'ref' : 'value';
 
-    final holderVarName =
-        w.wrapperLevelUniqueNamer.makeUnique('_$globalVarName');
     s.write(
-        '${w.ffiLibraryPrefix}.Pointer<${type.getCType(w)}> $holderVarName;\n');
-    s.write(
-        "${type.getDartType(w)} get $globalVarName => ($holderVarName ??= ${w.dylibIdentifier}.lookup<${type.getCType(w)}>('$originalName')).value;\n\n");
+        "late final ${w.ffiLibraryPrefix}.Pointer<$dartType> $pointerName = ${w.dylibIdentifier}.lookup<$cType>('$originalName');\n\n");
+    s.write('$dartType get $globalVarName => $pointerName.$refOrValue;\n\n');
+    if (type.broadType != BroadType.Struct) {
+      s.write(
+          'set $globalVarName($dartType value) => $pointerName.value = value;\n\n');
+    }
 
     return BindingString(type: BindingStringType.global, string: s.toString());
   }
diff --git a/pkgs/ffigen/lib/src/config_provider/config.dart b/pkgs/ffigen/lib/src/config_provider/config.dart
index 96ca643..6c11b34 100644
--- a/pkgs/ffigen/lib/src/config_provider/config.dart
+++ b/pkgs/ffigen/lib/src/config_provider/config.dart
@@ -51,6 +51,10 @@
   Declaration get unnamedEnumConstants => _unnamedEnumConstants;
   late Declaration _unnamedEnumConstants;
 
+  /// Declaration config for Globals.
+  Declaration get globals => _globals;
+  late Declaration _globals;
+
   /// Declaration config for Macro constants.
   Declaration get macroDecl => _macroDecl;
   late Declaration _macroDecl;
@@ -222,6 +226,15 @@
         extractedResult: (dynamic result) =>
             _unnamedEnumConstants = result as Declaration,
       ),
+      strings.globals: Specification<Declaration>(
+        requirement: Requirement.no,
+        validator: declarationConfigValidator,
+        extractor: declarationConfigExtractor,
+        defaultValue: () => Declaration(),
+        extractedResult: (dynamic result) {
+          _globals = result as Declaration;
+        },
+      ),
       strings.macros: Specification<Declaration>(
         requirement: Requirement.no,
         validator: declarationConfigValidator,
diff --git a/pkgs/ffigen/lib/src/header_parser/includer.dart b/pkgs/ffigen/lib/src/header_parser/includer.dart
index baa5b59..bd82476 100644
--- a/pkgs/ffigen/lib/src/header_parser/includer.dart
+++ b/pkgs/ffigen/lib/src/header_parser/includer.dart
@@ -47,6 +47,16 @@
   }
 }
 
+bool shouldIncludeGlobalVar(String usr, String name) {
+  if (bindingsIndex.isSeenGlobalVar(usr) || name == '') {
+    return false;
+  } else if (config.globals.shouldInclude(name)) {
+    return true;
+  } else {
+    return false;
+  }
+}
+
 bool shouldIncludeMacro(String usr, String name) {
   if (bindingsIndex.isSeenMacro(usr) || name == '') {
     return false;
diff --git a/pkgs/ffigen/lib/src/header_parser/sub_parsers/var_parser.dart b/pkgs/ffigen/lib/src/header_parser/sub_parsers/var_parser.dart
new file mode 100644
index 0000000..d0248ec
--- /dev/null
+++ b/pkgs/ffigen/lib/src/header_parser/sub_parsers/var_parser.dart
@@ -0,0 +1,47 @@
+// Copyright (c) 2021, 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/code_generator.dart';
+import 'package:ffigen/src/header_parser/data.dart';
+import 'package:ffigen/src/header_parser/includer.dart';
+import 'package:logging/logging.dart';
+
+import '../clang_bindings/clang_bindings.dart' as clang_types;
+import '../data.dart';
+import '../utils.dart';
+
+final _logger = Logger('ffigen.header_parser.var_parser');
+
+/// Parses a global variable
+Global? parseVarDeclaration(clang_types.CXCursor cursor) {
+  final name = cursor.spelling();
+  final usr = cursor.usr();
+  if (bindingsIndex.isSeenGlobalVar(usr)) {
+    return bindingsIndex.getSeenGlobalVar(usr);
+  }
+  if (!shouldIncludeGlobalVar(usr, name)) {
+    return null;
+  }
+
+  _logger.fine('++++ Adding Global: ${cursor.completeStringRepr()}');
+
+  final type = cursor.type().toCodeGenType();
+  if (type.getBaseType().broadType == BroadType.Unimplemented ||
+      type.getBaseType().isIncompleteStruct) {
+    _logger.fine(
+        '---- Removed Global, reason: unsupported type: ${cursor.completeStringRepr()}');
+    _logger.warning("Skipped global variable '$name', type not supported.");
+    return null;
+  }
+
+  final global = Global(
+    originalName: name,
+    name: config.globals.renameUsingConfig(name),
+    usr: usr,
+    type: type,
+    dartDoc: getCursorDocComment(cursor),
+  );
+  bindingsIndex.addGlobalVarToSeen(usr, global);
+  return global;
+}
diff --git a/pkgs/ffigen/lib/src/header_parser/translation_unit_parser.dart b/pkgs/ffigen/lib/src/header_parser/translation_unit_parser.dart
index 7c08410..69f7f13 100644
--- a/pkgs/ffigen/lib/src/header_parser/translation_unit_parser.dart
+++ b/pkgs/ffigen/lib/src/header_parser/translation_unit_parser.dart
@@ -6,6 +6,7 @@
 
 import 'package:ffigen/src/code_generator.dart';
 import 'package:ffigen/src/header_parser/sub_parsers/macro_parser.dart';
+import 'package:ffigen/src/header_parser/sub_parsers/var_parser.dart';
 import 'package:logging/logging.dart';
 
 import 'clang_bindings/clang_bindings.dart' as clang_types;
@@ -58,6 +59,9 @@
         case clang_types.CXCursorKind.CXCursor_MacroDefinition:
           saveMacroDefinition(cursor);
           break;
+        case clang_types.CXCursorKind.CXCursor_VarDecl:
+          addToBindings(parseVarDeclaration(cursor));
+          break;
         default:
           _logger.finer('rootCursorVisitor: CursorKind not implemented');
       }
diff --git a/pkgs/ffigen/lib/src/header_parser/utils.dart b/pkgs/ffigen/lib/src/header_parser/utils.dart
index f0a4127..28ca657 100644
--- a/pkgs/ffigen/lib/src/header_parser/utils.dart
+++ b/pkgs/ffigen/lib/src/header_parser/utils.dart
@@ -316,6 +316,7 @@
   final Map<String, EnumClass> _enumClass = {};
   final Map<String, Constant> _unnamedEnumConstants = {};
   final Map<String, String> _macros = {};
+  final Map<String, Global> _globals = {};
   // Stores only named typedefC used in NativeFunc.
   final Map<String, Typedef> _functionTypedefs = {};
 
@@ -367,6 +368,18 @@
     return _unnamedEnumConstants[usr];
   }
 
+  bool isSeenGlobalVar(String usr) {
+    return _globals.containsKey(usr);
+  }
+
+  void addGlobalVarToSeen(String usr, Global global) {
+    _globals[usr] = global;
+  }
+
+  Global? getSeenGlobalVar(String usr) {
+    return _globals[usr];
+  }
+
   bool isSeenMacro(String usr) {
     return _macros.containsKey(usr);
   }
diff --git a/pkgs/ffigen/lib/src/strings.dart b/pkgs/ffigen/lib/src/strings.dart
index 8f0ac93..99e0c68 100644
--- a/pkgs/ffigen/lib/src/strings.dart
+++ b/pkgs/ffigen/lib/src/strings.dart
@@ -39,6 +39,7 @@
 const structs = 'structs';
 const enums = 'enums';
 const unnamedEnums = 'unnamed-enums';
+const globals = 'globals';
 const macros = 'macros';
 
 // Sub-fields of Declarations.
diff --git a/pkgs/ffigen/pubspec.yaml b/pkgs/ffigen/pubspec.yaml
index adf2993..87663a2 100644
--- a/pkgs/ffigen/pubspec.yaml
+++ b/pkgs/ffigen/pubspec.yaml
@@ -3,7 +3,7 @@
 # BSD-style license that can be found in the LICENSE file.
 
 name: ffigen
-version: 2.0.0-dev.3
+version: 2.0.0-dev.4
 homepage: https://github.com/dart-lang/ffigen
 description: Experimental generator for FFI bindings, using LibClang to parse C header files.
 
diff --git a/pkgs/ffigen/test/code_generator_test.dart b/pkgs/ffigen/test/code_generator_test.dart
index ea6393b..aae8b0f 100644
--- a/pkgs/ffigen/test/code_generator_test.dart
+++ b/pkgs/ffigen/test/code_generator_test.dart
@@ -436,14 +436,23 @@
 /// The symbols are looked up in [dynamicLibrary].
 Bindings(ffi.DynamicLibrary dynamicLibrary): _dylib = dynamicLibrary;
 
-ffi.Pointer<ffi.Int32> _test1;
-int get test1 => (_test1 ??= _dylib.lookup<ffi.Int32>('test1')).value;
+late final ffi.Pointer<int> _test1 = _dylib.lookup<ffi.Int32>('test1');
 
-ffi.Pointer<ffi.Pointer<ffi.Float>> _test2;
-ffi.Pointer<ffi.Float> get test2 => (_test2 ??= _dylib.lookup<ffi.Pointer<ffi.Float>>('test2')).value;
+int get test1 => _test1.value;
 
-ffi.Pointer<ffi.Pointer<Some>> _test5;
-ffi.Pointer<Some> get test5 => (_test5 ??= _dylib.lookup<ffi.Pointer<Some>>('test5')).value;
+set test1(int value) => _test1.value = value;
+
+late final ffi.Pointer<ffi.Pointer<ffi.Float>> _test2 = _dylib.lookup<ffi.Pointer<ffi.Float>>('test2');
+
+ffi.Pointer<ffi.Float> get test2 => _test2.value;
+
+set test2(ffi.Pointer<ffi.Float> value) => _test2.value = value;
+
+late final ffi.Pointer<ffi.Pointer<Some>> _test5 = _dylib.lookup<ffi.Pointer<Some>>('test5');
+
+ffi.Pointer<Some> get test5 => _test5.value;
+
+set test5(ffi.Pointer<Some> value) => _test5.value = value;
 
 }
 
diff --git a/pkgs/ffigen/test/header_parser_tests/globals.h b/pkgs/ffigen/test/header_parser_tests/globals.h
new file mode 100644
index 0000000..f0f464f
--- /dev/null
+++ b/pkgs/ffigen/test/header_parser_tests/globals.h
@@ -0,0 +1,15 @@
+// Copyright (c) 2021, 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 <stdint.h>
+#include <stdbool.h>
+
+bool coolGlobal;
+int32_t myInt;
+int32_t *aGlobalPointer;
+long double longDouble;
+long double *pointerToLongDouble;
+
+// This should be ignored
+int GlobalIgnore;
diff --git a/pkgs/ffigen/test/header_parser_tests/globals_test.dart b/pkgs/ffigen/test/header_parser_tests/globals_test.dart
new file mode 100644
index 0000000..7184792
--- /dev/null
+++ b/pkgs/ffigen/test/header_parser_tests/globals_test.dart
@@ -0,0 +1,75 @@
+// Copyright (c) 2021, 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/code_generator.dart';
+import 'package:ffigen/src/header_parser.dart' as parser;
+import 'package:ffigen/src/config_provider.dart';
+import 'package:test/test.dart';
+import 'package:yaml/yaml.dart' as yaml;
+import 'package:ffigen/src/strings.dart' as strings;
+
+import '../test_utils.dart';
+
+late Library actual, expected;
+
+void main() {
+  group('globals_test', () {
+    setUpAll(() {
+      logWarnings();
+      expected = expectedLibrary();
+      actual = parser.parse(
+        Config.fromYaml(yaml.loadYaml('''
+${strings.name}: 'NativeLibrary'
+${strings.description}: 'Globals Test'
+${strings.output}: 'unused'
+${strings.headers}:
+  ${strings.entryPoints}:
+    - 'test/header_parser_tests/globals.h'
+  ${strings.includeDirectives}:
+    - '**globals.h'
+${strings.globals}:
+  ${strings.exclude}:
+    - GlobalIgnore
+# Needed for stdbool.h in MacOS
+${strings.compilerOpts}: '-I/Library/Developer/CommandLineTools/SDKs/MacOSX.sdk/System/Library/Frameworks/Kernel.framework/Headers/ -Wno-nullability-completeness'
+        ''') as yaml.YamlMap),
+      );
+    });
+
+    test('Total bindings count', () {
+      expect(actual.bindings.length, expected.bindings.length);
+    });
+
+    test('Parse global Values', () {
+      expect(actual.getBindingAsString('coolGlobal'),
+          expected.getBindingAsString('coolGlobal'));
+      expect(actual.getBindingAsString('myInt'),
+          expected.getBindingAsString('myInt'));
+      expect(actual.getBindingAsString('aGlobalPointer'),
+          expected.getBindingAsString('aGlobalPointer'));
+    });
+
+    test('Ignore global values', () {
+      expect(() => actual.getBindingAsString('GlobalIgnore'),
+          throwsA(TypeMatcher<NotFoundException>()));
+      expect(() => actual.getBindingAsString('longDouble'),
+          throwsA(TypeMatcher<NotFoundException>()));
+      expect(() => actual.getBindingAsString('pointerToLongDouble'),
+          throwsA(TypeMatcher<NotFoundException>()));
+    });
+  });
+}
+
+Library expectedLibrary() {
+  return Library(
+    name: 'Bindings',
+    bindings: [
+      Global(type: Type.boolean(), name: 'coolGlobal'),
+      Global(type: Type.nativeType(SupportedNativeType.Int32), name: 'myInt'),
+      Global(
+          type: Type.pointer(Type.nativeType(SupportedNativeType.Int32)),
+          name: 'aGlobalPointer'),
+    ],
+  );
+}
diff --git a/pkgs/ffigen/test/large_integration_tests/_expected_sqlite_bindings.dart b/pkgs/ffigen/test/large_integration_tests/_expected_sqlite_bindings.dart
index 7ea5be8..6abdd48 100644
--- a/pkgs/ffigen/test/large_integration_tests/_expected_sqlite_bindings.dart
+++ b/pkgs/ffigen/test/large_integration_tests/_expected_sqlite_bindings.dart
@@ -11,6 +11,44 @@
   /// The symbols are looked up in [dynamicLibrary].
   SQLite(ffi.DynamicLibrary dynamicLibrary) : _dylib = dynamicLibrary;
 
+  /// CAPI3REF: Run-Time Library Version Numbers
+  /// KEYWORDS: sqlite3_version sqlite3_sourceid
+  ///
+  /// These interfaces provide the same information as the [SQLITE_VERSION],
+  /// [SQLITE_VERSION_NUMBER], and [SQLITE_SOURCE_ID] C preprocessor macros
+  /// but are associated with the library instead of the header file.  ^(Cautious
+  /// programmers might include assert() statements in their application to
+  /// verify that values returned by these interfaces match the macros in
+  /// the header, and thus ensure that the application is
+  /// compiled with matching library and header files.
+  ///
+  /// <blockquote><pre>
+  /// assert( sqlite3_libversion_number()==SQLITE_VERSION_NUMBER );
+  /// assert( strncmp(sqlite3_sourceid(),SQLITE_SOURCE_ID,80)==0 );
+  /// assert( strcmp(sqlite3_libversion(),SQLITE_VERSION)==0 );
+  /// </pre></blockquote>)^
+  ///
+  /// ^The sqlite3_version[] string constant contains the text of [SQLITE_VERSION]
+  /// macro.  ^The sqlite3_libversion() function returns a pointer to the
+  /// to the sqlite3_version[] string constant.  The sqlite3_libversion()
+  /// function is provided for use in DLLs since DLL users usually do not have
+  /// direct access to string constants within the DLL.  ^The
+  /// sqlite3_libversion_number() function returns an integer equal to
+  /// [SQLITE_VERSION_NUMBER].  ^(The sqlite3_sourceid() function returns
+  /// a pointer to a string constant whose value is the same as the
+  /// [SQLITE_SOURCE_ID] C preprocessor macro.  Except if SQLite is built
+  /// using an edited copy of [the amalgamation], then the last four characters
+  /// of the hash might be different from [SQLITE_SOURCE_ID].)^
+  ///
+  /// See also: [sqlite_version()] and [sqlite_source_id()].
+  late final ffi.Pointer<ffi.Pointer<ffi.Int8>> _sqlite3_version =
+      _dylib.lookup<ffi.Pointer<ffi.Int8>>('sqlite3_version');
+
+  ffi.Pointer<ffi.Int8> get sqlite3_version => _sqlite3_version.value;
+
+  set sqlite3_version(ffi.Pointer<ffi.Int8> value) =>
+      _sqlite3_version.value = value;
+
   ffi.Pointer<ffi.Int8> sqlite3_libversion() {
     return (_sqlite3_libversion ??=
         _dylib.lookupFunction<_c_sqlite3_libversion, _dart_sqlite3_libversion>(
@@ -5458,6 +5496,111 @@
 
   _dart_sqlite3_sleep? _sqlite3_sleep;
 
+  /// CAPI3REF: Name Of The Folder Holding Temporary Files
+  ///
+  /// ^(If this global variable is made to point to a string which is
+  /// the name of a folder (a.k.a. directory), then all temporary files
+  /// created by SQLite when using a built-in [sqlite3_vfs | VFS]
+  /// will be placed in that directory.)^  ^If this variable
+  /// is a NULL pointer, then SQLite performs a search for an appropriate
+  /// temporary file directory.
+  ///
+  /// Applications are strongly discouraged from using this global variable.
+  /// It is required to set a temporary folder on Windows Runtime (WinRT).
+  /// But for all other platforms, it is highly recommended that applications
+  /// neither read nor write this variable.  This global variable is a relic
+  /// that exists for backwards compatibility of legacy applications and should
+  /// be avoided in new projects.
+  ///
+  /// It is not safe to read or modify this variable in more than one
+  /// thread at a time.  It is not safe to read or modify this variable
+  /// if a [database connection] is being used at the same time in a separate
+  /// thread.
+  /// It is intended that this variable be set once
+  /// as part of process initialization and before any SQLite interface
+  /// routines have been called and that this variable remain unchanged
+  /// thereafter.
+  ///
+  /// ^The [temp_store_directory pragma] may modify this variable and cause
+  /// it to point to memory obtained from [sqlite3_malloc].  ^Furthermore,
+  /// the [temp_store_directory pragma] always assumes that any string
+  /// that this variable points to is held in memory obtained from
+  /// [sqlite3_malloc] and the pragma may attempt to free that memory
+  /// using [sqlite3_free].
+  /// Hence, if this variable is modified directly, either it should be
+  /// made NULL or made to point to memory obtained from [sqlite3_malloc]
+  /// or else the use of the [temp_store_directory pragma] should be avoided.
+  /// Except when requested by the [temp_store_directory pragma], SQLite
+  /// does not free the memory that sqlite3_temp_directory points to.  If
+  /// the application wants that memory to be freed, it must do
+  /// so itself, taking care to only do so after all [database connection]
+  /// objects have been destroyed.
+  ///
+  /// <b>Note to Windows Runtime users:</b>  The temporary directory must be set
+  /// prior to calling [sqlite3_open] or [sqlite3_open_v2].  Otherwise, various
+  /// features that require the use of temporary files may fail.  Here is an
+  /// example of how to do this using C++ with the Windows Runtime:
+  ///
+  /// <blockquote><pre>
+  /// LPCWSTR zPath = Windows::Storage::ApplicationData::Current->
+  /// &nbsp;     TemporaryFolder->Path->Data();
+  /// char zPathBuf&#91;MAX_PATH + 1&#93;;
+  /// memset(zPathBuf, 0, sizeof(zPathBuf));
+  /// WideCharToMultiByte(CP_UTF8, 0, zPath, -1, zPathBuf, sizeof(zPathBuf),
+  /// &nbsp;     NULL, NULL);
+  /// sqlite3_temp_directory = sqlite3_mprintf("%s", zPathBuf);
+  /// </pre></blockquote>
+  late final ffi.Pointer<ffi.Pointer<ffi.Int8>> _sqlite3_temp_directory =
+      _dylib.lookup<ffi.Pointer<ffi.Int8>>('sqlite3_temp_directory');
+
+  ffi.Pointer<ffi.Int8> get sqlite3_temp_directory =>
+      _sqlite3_temp_directory.value;
+
+  set sqlite3_temp_directory(ffi.Pointer<ffi.Int8> value) =>
+      _sqlite3_temp_directory.value = value;
+
+  /// CAPI3REF: Name Of The Folder Holding Database Files
+  ///
+  /// ^(If this global variable is made to point to a string which is
+  /// the name of a folder (a.k.a. directory), then all database files
+  /// specified with a relative pathname and created or accessed by
+  /// SQLite when using a built-in windows [sqlite3_vfs | VFS] will be assumed
+  /// to be relative to that directory.)^ ^If this variable is a NULL
+  /// pointer, then SQLite assumes that all database files specified
+  /// with a relative pathname are relative to the current directory
+  /// for the process.  Only the windows VFS makes use of this global
+  /// variable; it is ignored by the unix VFS.
+  ///
+  /// Changing the value of this variable while a database connection is
+  /// open can result in a corrupt database.
+  ///
+  /// It is not safe to read or modify this variable in more than one
+  /// thread at a time.  It is not safe to read or modify this variable
+  /// if a [database connection] is being used at the same time in a separate
+  /// thread.
+  /// It is intended that this variable be set once
+  /// as part of process initialization and before any SQLite interface
+  /// routines have been called and that this variable remain unchanged
+  /// thereafter.
+  ///
+  /// ^The [data_store_directory pragma] may modify this variable and cause
+  /// it to point to memory obtained from [sqlite3_malloc].  ^Furthermore,
+  /// the [data_store_directory pragma] always assumes that any string
+  /// that this variable points to is held in memory obtained from
+  /// [sqlite3_malloc] and the pragma may attempt to free that memory
+  /// using [sqlite3_free].
+  /// Hence, if this variable is modified directly, either it should be
+  /// made NULL or made to point to memory obtained from [sqlite3_malloc]
+  /// or else the use of the [data_store_directory pragma] should be avoided.
+  late final ffi.Pointer<ffi.Pointer<ffi.Int8>> _sqlite3_data_directory =
+      _dylib.lookup<ffi.Pointer<ffi.Int8>>('sqlite3_data_directory');
+
+  ffi.Pointer<ffi.Int8> get sqlite3_data_directory =>
+      _sqlite3_data_directory.value;
+
+  set sqlite3_data_directory(ffi.Pointer<ffi.Int8> value) =>
+      _sqlite3_data_directory.value = value;
+
   /// CAPI3REF: Win32 Specific Interface
   ///
   /// These interfaces are available only on Windows.  The