Clone in a terminal:
Commit 3191744
Johan Mattsson - 2015-05-16T04:08:04+00:00
3191744314efdea21b9ca6d0cca953d8df2f6b18johan.mattsson.m@gmail.com

Merge branch 'master' of /home/johan/birdfont-android/../birdfont

Changed files (21)

Diff

diff --git a/birdfont/GtkWindow.vala b/birdfont/GtkWindow.valaindex 21ccd0e..9ce1c5b 100644--- a/birdfont/GtkWindow.vala+++ b/birdfont/GtkWindow.vala@@ -179,7 +179,7 @@ public class GtkWindow : Gtk.Window, NativeWindow { 		add (vbox); 		 		try {-			set_icon_from_file ((!) Icons.find_icon ("birdfont_window_icon.png").get_path ());+			set_icon_from_file ((!) SearchPaths.find_file (null, "birdfont_window_icon.png").get_path ()); 		} catch (GLib.Error e) { 			warning (e.message); 		}diff --git a/birdfont/Main.vala b/birdfont/Main.valaindex fb94318..7c20aa3 100644--- a/birdfont/Main.vala+++ b/birdfont/Main.vala@@ -23,7 +23,6 @@ public static int main (string[] arg) { 	string file; 	BirdFont.BirdFont birdfont; -	Icons.use_high_resolution (true); 	birdfont = new BirdFont.BirdFont (); 	birdfont.init (arg, null); 	Gtk.init (ref arg);@@ -36,50 +35,8 @@ public static int main (string[] arg) {  	birdfont.load_font_from_command_line (); -	load_ucd (); 	Gtk.main ();- 	return 0; } -/** Load descriptions from the unicode character database in a - * background thread.- */-void load_ucd () {	-	CharDatabaseParser db;-	unowned Thread<CharDatabaseParser> db_thread;-	Mutex database_mutex = new Mutex ();-	Cond main_loop_idle = new Cond ();-	bool in_idle = false;-	-	try {-		db = new CharDatabaseParser ();-		db_thread = Thread.create<CharDatabaseParser> (db.load, false);-		-		// wait until main loop is done-		db.sync.connect (() => {-			database_mutex.lock ();-			IdleSource idle = new IdleSource ();-			in_idle = false;-			-			idle.set_callback (() => {-				database_mutex.lock ();-				in_idle = true;-				main_loop_idle.broadcast ();-				database_mutex.unlock ();-				return false;-			});-			idle.attach (null);-			-			while (!in_idle) {-				main_loop_idle.wait (database_mutex);-			}-			-			database_mutex.unlock ();-		});-	} catch (GLib.Error e) {-		warning (e.message);-	}-}- diff --git a/configure b/configureindex 075c109..4a827d9 100755--- a/configure+++ b/configure@@ -71,15 +71,16 @@ def configure (gtk, libbgee, posixvala): 				'gtk+-3.0', 				'webkitgtk-3.0',  				'libsoup-2.4',-				'libnotify'+				'libnotify',+				'sqlite3' 				] 	else: 		libs = [ 				'gdk-pixbuf-2.0', 				'gio-2.0',  				'glib-2.0', +				'sqlite' 				]-	  	for lib in libs: 		if not test_library_version (lib):diff --git a/dodo.py b/dodo.pyindex 3a809cd..178183d 100644--- a/dodo.py+++ b/dodo.py@@ -44,6 +44,7 @@ DOIT_CONFIG = {  # external Vala libs LIBS = [+    'sqlite3',     'glib-2.0',     'gio-2.0',     'cairo',diff --git a/install.py b/install.pyindex b3f6af6..16f5bb6 100755--- a/install.py+++ b/install.py@@ -105,6 +105,8 @@ install ('resources/key_bindings.xml', '/share/birdfont', 644) install ('resources/roboto.bf', '/share/birdfont', 644) install ('resources/linux/birdfont_window_icon.png', '/share/birdfont', 644) install ('resources/linux/birdfont.desktop', '/share/applications', 644)+install ('resources/ucd.sqlite', '/share/birdfont', 644)+install ('resources/codepages.sqlite', '/share/birdfont', 644)  install ('resources/linux/256x256/birdfont.png', '/share/icons/hicolor/256x256/apps', 644) install ('resources/linux/128x128/birdfont.png', '/share/icons/hicolor/128x128/apps', 644)diff --git a/libbirdfont/Argument.vala b/libbirdfont/Argument.valaindex e41dbac..2902091 100644--- a/libbirdfont/Argument.vala+++ b/libbirdfont/Argument.vala@@ -1,5 +1,5 @@ /*-    Copyright (C) 2012 Johan Mattsson+    Copyright (C) 2012 2015 Johan Mattsson      This library is free software; you can redistribute it and/or modify      it under the terms of the GNU Lesser General Public License as @@ -16,18 +16,18 @@ namespace BirdFont { 	 public class Argument : GLib.Object { 	-	List<string> args;+	Gee.ArrayList<string> args; 	 	public Argument (string line) {-		args = new List<string> ();+		args = new Gee.ArrayList<string> (); 		set_argument (line); 	} 	 	public Argument.command_line (string[] arg) {	-		args = new List<string> ();+		args = new Gee.ArrayList<string> ();  		foreach (string a in arg) {-			args.append (a);+			args.add (a); 		} 	} 	@@ -35,8 +35,9 @@ public class Argument : GLib.Object { 	public int validate () { 		string prev = ""; 		int i = 0;-		foreach (string a in args) {-			+		string[] p;+		+		foreach (string a in args) {			 			if (a == "") { 				continue; 			}@@ -55,6 +56,11 @@ public class Argument : GLib.Object { 				continue; 			} +			if (a.index_of ("=") > -1) {+				p = a.split ("=");+				a = p[0];+			}+ 			// a single character, like -t 			if (!a.has_prefix ("--") && a.has_prefix ("-")) { 				a = expand_param (a);@@ -71,8 +77,9 @@ public class Argument : GLib.Object { 				a == "--mac" || 				a == "--android" || 				a == "--log" ||-				a == "--no-ucd" ||-				a == "--windows") {+				a == "--windows" ||+				a == "--parse-ucd" ||+				a == "--codepages") { 				prev = a; 				i++; 				continue;@@ -96,8 +103,8 @@ public class Argument : GLib.Object { 	public string get_file () { 		string f = ""; 		-		if (args.length () >= 2) {-			f = args.nth (1).data;+		if (args.size >= 2) {+			f = args.get (1); 		}  		if (f.has_prefix ("-")) {@@ -108,7 +115,7 @@ public class Argument : GLib.Object { 	} 	 	public void print_all () {-		print (@"$(args.length ()) arguments:\n");+		print (@"$(args.size) arguments:\n"); 		 		foreach (string p in args) { 			print (@"$p\n");@@ -124,7 +131,9 @@ public class Argument : GLib.Object { 		int i = 0; 		string? n; 		string p;-+		string v = "";+		string[] pm;+		 		if (param.substring (0, 1) != "-") { 			warning (@"parameters must begin with \"-\" got $param"); 			return null;@@ -132,10 +141,22 @@ public class Argument : GLib.Object {  		foreach (string s in args) { +			if (s.index_of ("=") > -1) {+				pm = s.split ("=");+				+				if (pm.length > 1) {+					v = pm[1];+				}+				+				s = pm[0];+			}+ 			// this is content not a parameter -			if (s.substring (0, 1) != "-") continue;+			if (s.substring (0, 1) != "-") {+				continue;+			} -			// we might need to expand -t to test fo instance+			// we might need to expand -t to test for instance 			if (s.substring (0, 2) != "--") { 				p = expand_param (s); 			} else {				@@ -143,20 +164,24 @@ public class Argument : GLib.Object { 			} 			 			if (param == p) {-				if (i + 2 >= args.length ()) {+				if (v != "") {+					return v;+				}+				+				if (i + 2 >= args.size) { 					return ""; 				} 				-				n = args.nth (i + 2).data;+				n = args.get (i + 2); 				if (n == null) { 					return ""; 				} 				-				if (args.nth (i + 2).data.substring (0, 1) == "-") {+				if (args.get (i + 2).substring (0, 1) == "-") { 					return ""; 				} 				-				return args.nth (i + 2).data;+				return args.get (i + 2); 			} 			 			i++;@@ -184,10 +209,14 @@ public class Argument : GLib.Object { 	private string expand_param (string? param) { 		if (param == null) return ""; 		var p = (!) param;++		if (p.get_char (0) != '-') {+			return "";+		} 		-		if (p.length == 0) return "";-		if (p.get_char (0) != '-') return "";-		if (p.char_count () != 2) return "";+		if (p.char_count () != 2) {+			return "";+		} 		 		switch (p.get_char (1)) { 			case 'c':@@ -235,17 +264,17 @@ public class Argument : GLib.Object { 				n = arg.substring (i, a - i + 1); 			} 					-			args.append (n);+			args.add (n); 			 			i += n.char_count () + 1; 		} while (i < arg.char_count ()); 	}  	public void print_help () -		requires (args.length () > 0)+		requires (args.size > 0) 	{ 		stdout.printf (t_("Usage") + ": ");-		stdout.printf (args.nth (0).data);+		stdout.printf (args.get (0)); 		stdout.printf (" [" + t_("FILE") + "] [" + t_("OPTION") + " ...]\n");  		print_padded ("-a, --android", t_("enable Android customizations"));diff --git a/libbirdfont/BirdFont.vala b/libbirdfont/BirdFont.valaindex 9d71c2d..b5d1b0a 100644--- a/libbirdfont/BirdFont.vala+++ b/libbirdfont/BirdFont.vala@@ -398,7 +398,9 @@ public class BirdFont { 		string theme; 		int default_theme_version; 		string theme_version;-		+		CharDatabaseParser parser;+		CodePageBits codepage_bits;+ 		args = new Argument.command_line (arg);  #if ANDROID@@ -524,6 +526,16 @@ public class BirdFont { 		if (TestBirdFont.get_singleton ().test_cases_to_run != "All") { 			TestBirdFont.run_tests (); 		}+		+		if (has_argument ("--parse-ucd")) {+			parser = new CharDatabaseParser ();+			parser.regenerate_database ();+		}++		if (has_argument ("--codepages")) {+			codepage_bits = new CodePageBits ();+			codepage_bits.generate_codepage_database ();+		} 	}  	public static Argument get_arguments () {diff --git a/libbirdfont/BirdFontFile.vala b/libbirdfont/BirdFontFile.valaindex bfe5260..87f1bc0 100644--- a/libbirdfont/BirdFontFile.vala+++ b/libbirdfont/BirdFontFile.vala@@ -377,12 +377,12 @@ class BirdFontFile : GLib.Object { 		write_glyph_collection_start (gc, os); 		write_selected (gc, os); 		foreach (Glyph g in gc.get_version_list ().glyphs) {-			write_glyph (g, gc, os);+			write_glyph (g, os); 		} 		write_glyph_collection_end (os); 	}  -	public void write_glyph (Glyph g, GlyphCollection gc, DataOutputStream os) throws GLib.Error {+	public void write_glyph (Glyph g, DataOutputStream os) throws GLib.Error { 		string data; 		 		os.put_string (@"\t<glyph id=\"$(g.version_id)\" left=\"$(double_to_string (g.left_limit))\" right=\"$(double_to_string (g.right_limit))\">\n");@@ -390,7 +390,10 @@ class BirdFontFile : GLib.Object { 			data = get_point_data (p); 			if (data != "") { 				os.put_string (@"\t\t<path ");-				os.put_string (@"stroke=\"$(double_to_string (p.stroke))\" ");+				+				if (p.stroke != 0) {+					os.put_string (@"stroke=\"$(double_to_string (p.stroke))\" ");+				} 				 				if (p.line_cap != LineCap.BUTT) { 					if (p.line_cap == LineCap.ROUND) {diff --git a/libbirdfont/BirdFontPart.vala b/libbirdfont/BirdFontPart.valaindex 61b0e2d..9a94419 100644--- a/libbirdfont/BirdFontPart.vala+++ b/libbirdfont/BirdFontPart.vala@@ -265,7 +265,7 @@ public class BirdFontPart : GLib.Object{ 		os = create_file (@"$(file_name).bfp", "glyphs", dir_name); 		bf.write_root_tag (os); 		bf.write_glyph_collection_start (gc, os);-		bf.write_glyph (g, gc, os);+		bf.write_glyph (g, os); 		bf.write_glyph_collection_end (os); 		bf.write_closing_root_tag (os); 		os.close ();diff --git a/libbirdfont/CharDatabase.vala b/libbirdfont/CharDatabase.valaindex cbfce9c..1a2dc3f 100644--- a/libbirdfont/CharDatabase.vala+++ b/libbirdfont/CharDatabase.vala@@ -1,5 +1,5 @@ /*-    Copyright (C) 2012 Johan Mattsson+    Copyright (C) 2012 2015 Johan Mattsson      This library is free software; you can redistribute it and/or modify      it under the terms of the GNU Lesser General Public License as @@ -13,32 +13,47 @@ */  using Gee;+using Sqlite;  namespace BirdFont {  public class CharDatabase {-	-	public static HashMap<string, string> entries;-	public static HashMultiMap<string, string> index;- 	public static GlyphRange full_unicode_range;-	public static bool database_is_loaded = false;++	public static unowned Database db;+	public static Database? database = null;  	public CharDatabase () {-		entries = new HashMap<string, string> ();-		index = new HashMultiMap<string, string> ();-	+		File f;+			 		full_unicode_range = new GlyphRange ();+		f = get_database_file ();+		open_database () ;+	}+	+	public static void open_database () {+		File f = get_database_file ();+		int rc = Database.open ((!) f.get_path (), out database);++		db = (!) database;++		if (rc != Sqlite.OK) {+			stderr.printf ("Can't open database: %d, %s\n", rc, db.errmsg ());+		}+	}+	+	public static File get_database_file () {+		return SearchPaths.find_file (null, "ucd.sqlite"); 	}  	public static GlyphRange search (string s) { 		GlyphRange result = new GlyphRange (); 		GlyphRange ucd_result = new GlyphRange ();+		int rc, cols;+		Statement statement;+		string select; 		unichar c; 		-		return_val_if_fail (!is_null (index), result);		-		return_val_if_fail (result.get_length () == 0, result);-		 		if (s.has_prefix ("U+") || s.has_prefix ("u+")) { 			c = Font.to_unichar (s.down ()); 			@@ -46,23 +61,49 @@ public class CharDatabase { 				result.add_single (c); 			} 		}-		+ 		if (s.char_count () == 1) {-			result.add_single (s.get_char ()); -		}-		-		foreach (string i in index.get (s)) {-			c = Font.to_unichar ("U+" + i.down ());-			ucd_result.add_single (c);+			result.add_single (s.get_char (0)); 		}++		select = "SELECT unicode FROM Words "+			 + "WHERE word = '" + s.replace ("'", "''") + "';";+					+		rc = db.prepare_v2 (select, select.length, out statement, null); 		-		try {-			if (ucd_result.get_length () > 0) {-				ucd_result.sort ();-				result.parse_ranges (ucd_result.get_all_ranges ());+		if (rc == Sqlite.OK) {+			cols = statement.column_count();+			+			if (cols != 1) {+				warning ("Expecting one column.");+				return result; 			}-		} catch (MarkupError e) {-			warning (e.message);++			while (true) {+				rc = statement.step ();+				+				if (rc == Sqlite.DONE) {+					break;+				} else if (rc == Sqlite.ROW) {+					c = (unichar) statement.column_int64 (0);+					ucd_result.add_single (c);+				} else {+					warning ("Error: %d, %s\n", rc, db.errmsg ());+					break;+				}+			}+			+			try {+				if (ucd_result.get_length () > 0) {+					ucd_result.sort ();+					result.parse_ranges (ucd_result.get_all_ranges ());+				}+			} catch (MarkupError e) {+				warning (e.message);+			}+			+		} else {+			warning ("SQL error: %d, %s\n", rc, db.errmsg ()); 		} 		 		return result;@@ -95,35 +136,45 @@ public class CharDatabase { 		return false;		 	} 	-	/** Convert from the U+xx form to the unicode database hex value. */ -	static string to_database_hex (unichar c) {-		string hex_char = Font.to_hex (c).replace ("U+", "");--		if (hex_char.char_count () == 2) {-			hex_char = "00" + hex_char;-		}-		-		if (hex_char.char_count () == 6 && hex_char.has_prefix ("0")) {-			hex_char = hex_char.substring (1);-		}-		-		hex_char = hex_char.up ();		-		return hex_char;-	}-	 	public static string get_unicode_database_entry (unichar c) {-		string description;-		string? d;+		string description = "";+		int rc, cols;+		Statement statement;+		string select = "SELECT description FROM Description "+			+ @"WHERE unicode = $((int64) c)"; 		-		d = entries.get (to_database_hex (c));+		rc = db.prepare_v2 (select, select.length, out statement, null); 		-		if (d == null) {-			description = Font.to_hex (c).replace ("U+", "") + "\tUNICODE CHARACTER";+		if (rc == Sqlite.OK) {+			cols = statement.column_count();+			+			if (cols != 1) {+				warning ("Expecting one column.");+				return description;+			}++			while (true) {+				rc = statement.step ();+				+				if (rc == Sqlite.DONE) {+					break;+				} else if (rc == Sqlite.ROW) {+					description = statement.column_text (0);+				} else {+					printerr ("Error: %d, %s\n", rc, db.errmsg ());+					break;+				}+			}+					 		} else {-			description = (!) d;+			printerr ("SQL error: %d, %s\n", rc, db.errmsg ());+		}+		+		if (description == "") {+			description = Font.to_hex (c).replace ("U+", "") + "\tUNICODE CHARACTER"; 		} 		-		return description;		+		return description; 	} 	 	public static void get_full_unicode (GlyphRange glyph_range) {diff --git a/libbirdfont/CharDatabaseParser.vala b/libbirdfont/CharDatabaseParser.valaindex 7de6584..2c00ab7 100644--- a/libbirdfont/CharDatabaseParser.vala+++ b/libbirdfont/CharDatabaseParser.vala@@ -1,5 +1,5 @@ /*-    Copyright (C) 2013 Johan Mattsson+    Copyright (C) 2013 2015 Johan Mattsson      This library is free software; you can redistribute it and/or modify      it under the terms of the GNU Lesser General Public License as @@ -13,18 +13,120 @@ */  using Gee;+using Sqlite;  namespace BirdFont {  public class CharDatabaseParser : GLib.Object {+	public static unowned Database db;+	public static Database? database = null; -	public signal void sync ();-	 	GlyphRange utf8 = new GlyphRange (); 	 	public CharDatabaseParser () {	 	} +	public File get_database_file () {+		string? fn = BirdFont.get_argument ("--parse-ucd");+		+		if (fn != null && ((!) fn) != "") {+			return File.new_for_path ((!) fn);+		}+		+		return File.new_for_path ("ucd.sqlite");+	}+	+	public void regenerate_database () {+		File f = get_database_file ();+		+		stdout.printf ("Generating sqlite database in: %s\n", (!) f.get_path ());+		+		try {+			if (f.query_exists ()) {+				f.delete ();+			}+			+			open_database ();+			create_tables ();+			parse_all_entries ();+		} catch (GLib.Error e) {+			warning (e.message);+		}+	}+	+	public void open_database () {+		File f = get_database_file ();+		int rc = Database.open ((!) f.get_path (), out database);++		db = (!) database;++		if (rc != Sqlite.OK) {+			stderr.printf ("Can't open database: %d, %s\n", rc, db.errmsg ());+		}+	}+	+	public void create_tables () {+		int ec;+		string? errmsg;+		string description_table = """+			CREATE TABLE Description (+				unicode        INTEGER     PRIMARY KEY    NOT NULL,+				description    TEXT                       NOT NULL+			);+		""";++		ec = db.exec (description_table, null, out errmsg);+		if (ec != Sqlite.OK) {+			warning ("Error: %s\n", (!) errmsg);+		}++		string index_table = """+			CREATE TABLE Words (+				unicode        INTEGER     NOT NULL,+				word           TEXT        NOT NULL+			);+		""";++		ec = db.exec (index_table, null, out errmsg);+		if (ec != Sqlite.OK) {+			warning ("Error: %s\n", (!) errmsg);+		}++		string create_index = "CREATE INDEX word_index ON Words (word);";++		ec = db.exec (create_index, null, out errmsg);+		if (ec != Sqlite.OK) {+			warning ("Error: %s\n", (!) errmsg);+		}+	}++	public void insert_lookup (int64 character, string word) {+		string? errmsg;+		string query = """+			INSERT INTO Words (unicode, word)+			VALUES (""" + @"$((int64) character)" + """, '""" + word.replace ("'", "''") + "');";+		int ec = db.exec (query, null, out errmsg);+		if (ec != Sqlite.OK) {+			stderr.printf (query);+			warning ("Error: %s\n", (!) errmsg);+		}+	}+	+	public void insert_entry (int64 character, string description) {+		string? errmsg;+		string query = """+			INSERT INTO Description (unicode, description)+			VALUES (""" + @"$((int64) character)" + """, '""" + description.replace ("'", "''") + "');";+		+		int ec = db.exec (query, null, out errmsg);+		+		if (ec != Sqlite.OK) {+			stderr.printf (query);+			warning ("Error: %s\n", (!) errmsg);+			warning (@"Can't insert description to: $(character)");+		}+	}+ 	private void add_entry (string data) { 		string[] e; 		string[] r;@@ -61,13 +163,8 @@ public class CharDatabaseParser : GLib.Object { 		unicode_hex = e[0].up (); 		 		ch = Font.to_unichar ("U+" + unicode_hex.down ());-		-		Idle.add (() => {-			CharDatabase.entries.set (unicode_hex, data);-			return false;-		});-		sync ();-		+		stdout.printf ("Adding " + (!) ch.to_string () + "\n");+		insert_entry ((int64) ch, data); 		utf8.add_single (ch); 		 		foreach (string s in e) {@@ -76,11 +173,7 @@ public class CharDatabaseParser : GLib.Object { 				d = t.split (" "); 				foreach (string token in d) { 					if (token != "") {-						Idle.add (() => {-							CharDatabase.index.set (token, unicode_hex);-							return false;-						});-						sync ();+						insert_lookup ((int64)ch, token); 					} 				} 			}@@ -94,14 +187,17 @@ public class CharDatabaseParser : GLib.Object { 		string data; 		string description = ""; 		File file;+		int ec;+		string? errmsg;+		uint64 transaction_number = 0;+		+		file = get_unicode_database (); -		if (BirdFont.has_argument ("--no-ucd")) {-			warning ("Not loading UCD.");-			return;+		ec = db.exec ("BEGIN TRANSACTION", null, out errmsg);+		if (ec != Sqlite.OK) {+			warning ("Error: %s\n", (!) errmsg); 		}--		file = get_unicode_database ();-		+				 		try { 			fin = file.read (); 			din = new DataInputStream (fin);@@ -119,6 +215,23 @@ public class CharDatabaseParser : GLib.Object { 					} else { 						if (description.index_of ("<not a character>") == -1) { 							add_entry (description);+							transaction_number++;+							+							if (transaction_number >= 1000) {+								print ("Write to database\n");+								+								ec = db.exec ("END TRANSACTION", null, out errmsg);+								if (ec != Sqlite.OK) {+									warning ("Error: %s\n", (!) errmsg);+								}								++								ec = db.exec ("BEGIN TRANSACTION", null, out errmsg);+								if (ec != Sqlite.OK) {+									warning ("Error: %s\n", (!) errmsg);+								}+								+								transaction_number = 0;	+							}  						} 						break; 					}					@@ -139,23 +252,16 @@ public class CharDatabaseParser : GLib.Object { 			warning (e.message); 			warning ("In %s", (!) get_unicode_database ().get_path ()); 		}-	}-	-	public CharDatabaseParser load () {-		parse_all_entries (); 		-		IdleSource idle = new IdleSource ();-		idle.set_callback (() => {-			CharDatabase.full_unicode_range = utf8;-			CharDatabase.database_is_loaded = true;-			return false;-		});-		idle.attach (null);-		-		return this;+		ec = db.exec ("END TRANSACTION", null, out errmsg);+		if (ec != Sqlite.OK) {+			warning ("Error: %s\n", (!) errmsg);+		}+				+		stdout.printf ("Done"); 	} -	static File get_unicode_database () {+	File get_unicode_database () { 		return SearchPaths.get_char_database (); 	} }diff --git a/libbirdfont/FallbackFont.vala b/libbirdfont/FallbackFont.valanew file mode 100644index 0000000..4430358--- /dev/null+++ b/libbirdfont/FallbackFont.vala@@ -0,0 +1,121 @@+/*+    Copyright (C) 2015 Johan Mattsson++    This library is free software; you can redistribute it and/or modify +    it under the terms of the GNU Lesser General Public License as +    published by the Free Software Foundation; either version 3 of the +    License, or (at your option) any later version.++    This library is distributed in the hope that it will be useful, but +    WITHOUT ANY WARRANTY; without even the implied warranty of +    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +    Lesser General Public License for more details.+*/++using Gee;+using Sqlite;++namespace BirdFont {++public class FallbackFont : GLib.Object {+	public static unowned Database db;+	public static Database? database = null;++	public FallbackFont () {	+	}++	public File get_database_file () {+		return SearchPaths.find_file (null, "fallback-font.sqlite");+	}+	+	public File get_new_database_file () {+		string? fn = BirdFont.get_argument ("--fallback-font");+		+		if (fn != null && ((!) fn) != "") {+			return File.new_for_path ((!) fn);+		}+		+		return File.new_for_path ("fallback-font.sqlite");+	}+		+	public void generate_fallback_font () {+		File f = get_new_database_file ();+		string? fonts = BirdFont.get_argument ("--fonts");+		string fallback;+		+		if (fonts == null) {+			stderr.printf ("Add a list of fonts to use as fallback to the \"--fonts\" argument.\n");+			stderr.printf ("Separate each font file with \":\"\n");+			return;+		}+		+		fallback = (!) fonts;+		+		stdout.printf ("Generating fallback font: %s\n", (!) f.get_path ());+		+		try {+			if (f.query_exists ()) {+				f.delete ();+			}+			+			open_database (f);+			create_tables ();+			+			foreach (string font in fallback.split (":")) {+				add_font (font);+			}		+		} catch (GLib.Error e) {+			warning (e.message);+		}+		+	}++	public void add_font (string font_file) {+		Font font;+		Glyph g;+		BirdFontFile bf;+		File single_glyph_font;+		+		font = new Font ();+		single_glyph_font = File.new_for_path ("/tmp/fallback_glyph.bf");+		+		font.set_file (font_file);+		if (!font.load ()) {+			stderr.printf ("Failed to load font: " + font_file);+			return;+		}+		+		for (int i = 0; i < font.length (); i++) {+			g = (!) font.get_glyph_indice (i);+			bf = new BirdFontFile (font);+		}+	}++	public void open_database (File db_file) {+		int rc = Database.open ((!) db_file.get_path (), out database);++		db = (!) database;++		if (rc != Sqlite.OK) {+			stderr.printf ("Can't open database: %d, %s\n", rc, db.errmsg ());+		}+	}++	public void create_tables () {+		int ec;+		string? errmsg;+		string create_font_table = """+			CREATE TABLE FallbackFont (+				unicode        INTEGER     PRIMARY KEY    NOT NULL,+				font_data      TEXT                       NOT NULL+			);+		""";+		+		ec = db.exec (create_font_table, null, out errmsg);+		if (ec != Sqlite.OK) {+			warning ("Error: %s\n", (!) errmsg);+		}+	}+}++}diff --git a/libbirdfont/OpenFontFormat/CodePageBits.vala b/libbirdfont/OpenFontFormat/CodePageBits.valaindex 17373de..cfebae6 100644--- a/libbirdfont/OpenFontFormat/CodePageBits.vala+++ b/libbirdfont/OpenFontFormat/CodePageBits.vala@@ -1,5 +1,5 @@ /*-    Copyright (C) 2014 Johan Mattsson+    Copyright (C) 2014 2015 Johan Mattsson      This library is free software; you can redistribute it and/or modify      it under the terms of the GNU Lesser General Public License as @@ -12,28 +12,32 @@     Lesser General Public License for more details. */ +using Sqlite;+ namespace BirdFont {  public class CodePageBits : GLib.Object {  	/** The first characters in all code pages. */ 	PageBit default_range;-	-	static bool has_codepages = false; 	static Gee.ArrayList<PageBit> codepages; -	-	public CodePageBits () {-		default_range = new PageBit (-1, "null-");+	static Gee.ArrayList<string> all_characters; ++	public static unowned Database db;+	public static Database? database = null; 		-		if (!has_codepages) {-			codepages = new Gee.ArrayList<PageBit> ();-			create_codepage_list ();-			has_codepages = true;+	public CodePageBits () {+		if (database == null) {+			open_database (get_database_file ()); 		} 	}++	public File get_database_file () {+		return SearchPaths.find_file (null, "codepages.sqlite");+	} 	 	public void get_pages (Font font, out uint32 p0, out uint32 p1) {-		uint32 indice;+		uint32 indice, a0, a1; 		GlyphCollection? gl; 		GlyphCollection g; 		@@ -43,46 +47,52 @@ public class CodePageBits : GLib.Object { 		for (indice = 0; (gl = font.get_glyph_collection_indice (indice)) != null; indice++) {		 			g = (!) gl; 			-			if (default_range.has_char (g.get_unicode_character ())) {-				set_bit (0, ref p0, ref p1);-			} else {-				set_bits_for_glyph (g, ref p0, ref p1);-			}-		}-	}--	void set_bits_for_glyph (GlyphCollection g, ref uint32 p0, ref uint32 p1) {-		Gee.ArrayList<int> bits;-		-		if (!g.is_unassigned ()) {-			bits = get_bits (g.get_unicode_character ());-						-			foreach (int bit in bits) {-				set_bit (bit, ref p0, ref p1);+			if (!g.is_unassigned ()) {+				get_bits (g.get_unicode_character (), out a0, out a1);+				p0 |= a0;+				p1 |= a1; 			} 		} 	} 	-	public Gee.ArrayList<int> get_bits (unichar c) {-		Gee.ArrayList<int> bits = new Gee.ArrayList<int> ();-		foreach (PageBit pb in codepages) {-			if (pb.has_char (c)) {-				bits.add (pb.bit); +	public void get_bits (unichar ch, out uint p0, out uint p1) {+		int rc, cols;+		Statement statement;+		int64 c = (int64) ch;+		string select = "SELECT codepages1, codepages2 FROM CodePages "+			 + "WHERE unicode = " + @"$c" + ";";+		+		p0 = 0;	+		p1 = 0;+		+		rc = db.prepare_v2 (select, select.length, out statement, null);+		+		if (rc == Sqlite.OK) {+			cols = statement.column_count();+			+			if (cols != 2) {+				warning ("Expecting two columns.");+				return; 			}-		}-		return bits;-	} -	void set_bit (int bit, ref uint32 p0, ref uint32 p1) {-		const int length = 32;-		-		if (bit	< length) {-			p0 |= 1 << bit;+			while (true) {+				rc = statement.step ();+				+				if (rc == Sqlite.DONE) {+					break;+				} else if (rc == Sqlite.ROW) {+					p0 = (uint) statement.column_int64 (0);+					p1 = (uint) statement.column_int64 (1);+				} else {+					printerr ("Error: %d, %s\n", rc, db.errmsg ());+					break;+				}+			} 		} else {-			p1 |= 1 << (bit - length);+			warning ("Database error: %s",  db.errmsg ()); 		} 	}-+	 	void create_codepage_list () { 		// TODO: Add ASMO  		// Windows-1252@@ -149,11 +159,157 @@ public class CodePageBits : GLib.Object { 		create_codepage (63, "- ß-â ä-ï Ä-Ç É ö-÷ ñ-ô ù-ü ÿ Ö Ü  -£ ¥ ₧ ƒ Ñ ¿ ⌐ ª-¬ º-½ ▐-▓ │ ┤ ┐ └ ┴ ┬ ├ ─ ┼ ═-╬ ┘ ┌ █ ▄ ▌ ▀ α Γ π Σ σ-τ µ Φ Θ Ω δ-ε ∞ φ ∩ ≡ °-² ≤-≥ ⌠-⌡ ≈ ∙-√ · ⁿ ■");		 	} -	void create_codepage (int bit, string ranges) {-		PageBit b = new PageBit (bit, ranges);+	void create_codepage (int bit, string characters) {+		string c;+		PageBit b = new PageBit (bit, characters); 		codepages.add (b);+		+		for (int i = 0; i < b.ranges.length (); i++) {+			c = b.ranges.get_char (i);+			if (all_characters.index_of (c) == -1) {+				all_characters.add (c);+			}+		}+	}+	+	File get_new_database_file () {+		string? fn = BirdFont.get_argument ("--codepages");+		+		if (fn != null && ((!) fn) != "") {+			return File.new_for_path ((!) fn);+		}+		+		return File.new_for_path ("codepages.sqlite");+	}+		+	public void generate_codepage_database () {+		File f = get_new_database_file ();++		stdout.printf ("Generating codepage database: %s\n", (!) f.get_path ());++		try {+			if (f.query_exists ()) {+				f.delete ();+			}+			+			open_database (f);+			create_tables ();+		+			default_range = new PageBit (-1, "null-");+			codepages = new Gee.ArrayList<PageBit> ();+			all_characters = new Gee.ArrayList<string> ();+			create_codepage_list ();+			+			write_database ();+		} catch (GLib.Error e) {+			warning (e.message);+		}+		+		stdout.printf ("Done\n");+	}++	void write_database () {+		unichar ch;+		uint32 pages1, pages2;+		string? errmsg;+		+		int ec = db.exec ("BEGIN TRANSACTION", null, out errmsg);+		if (ec != Sqlite.OK) {+			warning ("Error: %s\n", (!) errmsg);+		}+		+		foreach (string c in all_characters) {+			ch = c.get_char (0);+			get_pages_for_character (ch, out pages1, out pages2);+			insert_codepage_for_character ((int64) ch, pages1, pages2);+		}+		+		ec = db.exec ("END TRANSACTION", null, out errmsg);+		if (ec != Sqlite.OK) {+			warning ("Error: %s\n", (!) errmsg);+		}+	}++	void insert_codepage_for_character (int64 character, uint32 codepages1, uint32 codepages2) {+		string? errmsg;+		string query = """+			INSERT INTO CodePages (unicode, codepages1, codepages2)+			VALUES (""" + @"$((int64) character)" + ", " + @"$(codepages1), " + @"$(codepages2)" + ");";+		int ec = db.exec (query, null, out errmsg);+		if (ec != Sqlite.OK) {+			stderr.printf (query);+			warning ("Error: %s\n", (!) errmsg);+		}+	}+	+	void open_database (File db_file) {+		int rc = Database.open ((!) db_file.get_path (), out database);++		db = (!) database;++		if (rc != Sqlite.OK) {+			stderr.printf ("Can't open database: %d, %s\n", rc, db.errmsg ());+		}+	}++	void create_tables () {+		int ec;+		string? errmsg;+		string create_font_table = """+			CREATE TABLE CodePages (+				unicode        INTEGER     PRIMARY KEY    NOT NULL,+				codepages1     INTEGER                    NOT NULL,+				codepages2     INTEGER                    NOT NULL+			);+		""";+		+		ec = db.exec (create_font_table, null, out errmsg);+		if (ec != Sqlite.OK) {+			warning ("Error: %s\n", (!) errmsg);+		}+	}++	void get_pages_for_character (unichar character, out uint32 p0, out uint32 p1) {+		p0 = 0;+		p1 = 0;+	+		if (default_range.has_char (character)) {+			set_bit (0, ref p0, ref p1);+		} else {+			set_bits_for_character (character, ref p0, ref p1);+		} 	} +	void set_bits_for_character (unichar c, ref uint32 p0, ref uint32 p1) {+		Gee.ArrayList<int> bits;+		+		bits = get_code_page_bits (c);+					+		foreach (int bit in bits) {+			set_bit (bit, ref p0, ref p1);+		}+	}+	+	Gee.ArrayList<int> get_code_page_bits (unichar c) {+		Gee.ArrayList<int> bits = new Gee.ArrayList<int> ();+		foreach (PageBit pb in codepages) {+			if (pb.has_char (c)) {+				bits.add (pb.bit); +			}+		}+		return bits;+	}+	+	void set_bit (int bit, ref uint32 p0, ref uint32 p1) {+		const int length = 32;+		+		if (bit	< length) {+			p0 |= 1 << bit;+		} else {+			p1 |= 1 << (bit - length);+		}+	}+	 	private class PageBit : GLib.Object { 		public GlyphRange ranges; 		public int bit;diff --git a/libbirdfont/Path.vala b/libbirdfont/Path.valaindex 41bc4b8..b504d1b 100644--- a/libbirdfont/Path.vala+++ b/libbirdfont/Path.vala@@ -1290,7 +1290,7 @@ public class Path { 			ep.get_left_handle ().set_point_type (PointType.LINE_DOUBLE_CURVE); 			ep.type = PointType.DOUBLE_CURVE; 		} else {-			warning ("Point types: $right and $left in insert_new_point_on_path");+			warning (@"Point types: $right and $left in insert_new_point_on_path"); 		}  		ep.get_left_handle ().parent = ep;diff --git a/libbirdfont/StrokeTool.vala b/libbirdfont/StrokeTool.valaindex be5f7cf..42cb104 100644--- a/libbirdfont/StrokeTool.vala+++ b/libbirdfont/StrokeTool.vala@@ -71,20 +71,6 @@ public class StrokeTool : Tool { 		convert_stroke = false; 	} 	-	public PathList merge_selected_paths () {-		PathList n = new PathList ();-		Glyph g = MainWindow.get_current_glyph ();-		-		foreach (Path p in g.active_paths) {-			if (p.stroke == 0) {-				n.add (p);-			}-		}-		-		n = merge (n);-		return n;-	}-	 	public static PathList get_stroke_fast (Path path, double thickness) { 		PathList o; 		Path stroke;@@ -114,7 +100,21 @@ public class StrokeTool : Tool { 				 		return m; 	}-	++	public PathList merge_selected_paths () {+		PathList n = new PathList ();+		Glyph g = MainWindow.get_current_glyph ();+		+		foreach (Path p in g.active_paths) {+			if (p.stroke == 0) {+				n.add (p);+			}+		}+		+		n = merge (n);+		return n;+	}+		 	static Path simplify_stroke (Path p) { 		Path simplified = new Path (); 		Path segment, added_segment;@@ -272,7 +272,7 @@ public class StrokeTool : Tool { 		PathList r = new PathList (); 		 		foreach (Path p in pl.paths) {-			if (p.points.size > 22) {+			if (p.points.size > 7) { 				r.add (p); 			} else if (!has_new_corner (p)) { 				r.add (p);diff --git a/libbirdfont/TestCases.vala b/libbirdfont/TestCases.valaindex b8cb5ea..6d47f18 100644--- a/libbirdfont/TestCases.vala+++ b/libbirdfont/TestCases.vala@@ -84,20 +84,25 @@ class TestCases { 	 	public static void test_codepages () { 		CodePageBits pages = new CodePageBits ();+		uint32 p0, p1; 		-		if (pages.get_bits ('ó').size == 0) {+		pages.get_bits ('ó', out p0, out p1);+		if (p0 == 0 && p1 == 0) { 			warning ("Codepage for Hungarian is not set."); 		} 		-		if (pages.get_bits ('ö').size == 0) {+		pages.get_bits ('ö', out p0, out p1);+		if (p0 == 0 && p1 == 0) { 			warning ("Codepage for Swedish is not set."); 		} -		if (pages.get_bits ('ツ').size == 0) {+		pages.get_bits ('ツ', out p0, out p1);+		if (p0 == 0 && p1 == 0) { 			warning ("Codepage for Japanese is not set."); 		} -		if (pages.get_bits ('马').size == 0) {+		pages.get_bits ('马', out p0, out p1);+		if (p0 == 0 && p1 == 0) { 			warning ("Codepage for Chinese is not set."); 		} 	}diff --git a/libbirdgems/fit_cubic.c b/libbirdgems/fit_cubic.cindex 4cf1142..2817711 100644--- a/libbirdgems/fit_cubic.c+++ b/libbirdgems/fit_cubic.c@@ -69,7 +69,7 @@ void fit_bezier_curve_to_line ( 	Point2* points; 	int npoints; -	if (npoints % 2 != 0) {+	if (lines_size % 2 != 0) { 		fprintf (stderr, "Odd number of coordinates in fit_bezier_curve_to_line.");		 		return; 	}diff --git a/resources/codepages.sqlite b/resources/codepages.sqlitenew file mode 100644index 0000000..7c9e5b4Binary files /dev/null and b/resources/codepages.sqlite differdiff --git a/resources/ucd.sqlite b/resources/ucd.sqlitenew file mode 100644index 0000000..2464f03Binary files /dev/null and b/resources/ucd.sqlite differdiff --git a/scripts/build.py b/scripts/build.pyindex 6e17d7e..d4da979 100644--- a/scripts/build.py+++ b/scripts/build.py@@ -49,6 +49,7 @@ def libbirdfont(prefix, cc, cflags, ldflags, valac, valaflags, library, nonNull  		--pkg cairo \ 		--pkg libbirdxml \ 		--pkg libbirdgems \+		--pkg sqlite3 \ 		""") 	 	#copy c sources @@ -61,6 +62,7 @@ def libbirdfont(prefix, cc, cflags, ldflags, valac, valaflags, library, nonNull  			-c build/libbirdfont/*.c \ 			-fPIC \ 			-D 'GETTEXT_PACKAGE="birdfont"' \+			$(pkg-config --cflags sqlite) \ 			$(pkg-config --cflags """ + config.GEE + """) \ 			$(pkg-config --cflags gio-2.0) \ 			$(pkg-config --cflags cairo) \@@ -78,6 +80,7 @@ def libbirdfont(prefix, cc, cflags, ldflags, valac, valaflags, library, nonNull  			-shared \ 			""" + sonameparam + """ \ 			build/libbirdfont/*.o \+			$(pkg-config --libs sqlite) \ 			$(freetype-config --libs) \ 			$(pkg-config --libs """ + config.GEE + """) \ 			$(pkg-config --libs gio-2.0) \diff --git a/sqlite3.vapi b/sqlite3.vapinew file mode 100644index 0000000..edf6d62--- /dev/null+++ b/sqlite3.vapi@@ -0,0 +1,457 @@+/* sqlite3.vala+ *+ * Copyright (C) 2007 Jürg Billeter+ *+ * This library is free software; you can redistribute it and/or+ * modify it under the terms of the GNU Lesser General Public+ * License as published by the Free Software Foundation; either+ * version 2.1 of the License, or (at your option) any later version.++ * This library is distributed in the hope that it will be useful,+ * but WITHOUT ANY WARRANTY; without even the implied warranty of+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU+ * Lesser General Public License for more details.++ * You should have received a copy of the GNU Lesser General Public+ * License along with this library; if not, write to the Free Software+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301  USA+ *+ * Author:+ * 	Jürg Billeter <j@bitron.ch>+ */++[CCode (lower_case_cprefix = "sqlite3_", cheader_filename = "sqlite3.h")]+namespace Sqlite {+	/* Database Connection Handle */+	[Compact]+	[CCode (free_function = "sqlite3_close", cname = "sqlite3", cprefix = "sqlite3_")]+	public class Database {+		public int busy_timeout (int ms);+		public int changes ();+		[CCode (cname = "sqlite3_exec")]+		public int _exec (string sql, Callback? callback = null, [CCode (type = "char**")] out unowned string errmsg = null);+		[CCode (cname = "_sqlite3_exec")]+		public int exec (string sql, Callback? callback = null, out string errmsg = null) {+			unowned string sqlite_errmsg;+			var ec = this._exec (sql, callback, out sqlite_errmsg);+			if (&errmsg != null) {+				errmsg = sqlite_errmsg;+			}+			Sqlite.Memory.free ((void*) sqlite_errmsg);+			return ec;+		}+		public int extended_result_codes (int onoff);+		public int get_autocommit ();+		public void interrupt ();+		public int64 last_insert_rowid ();+		public int limit (Sqlite.Limit id, int new_val);+		public int total_changes ();+		public int complete (string sql);+		[CCode (cname = "sqlite3_get_table")]+		public int _get_table (string sql, [CCode (array_length = false)] out unowned string[] resultp, out int nrow, out int ncolumn, [CCode (type = "char**")] out unowned string? errmsg = null);+		private static void free_table ([CCode (array_length = false)] string[] result);+		[CCode (cname = "_sqlite3_get_table")]+		public int get_table (string sql, out string[] resultp, out int nrow, out int ncolumn, out string? errmsg = null) {+			unowned string? sqlite_errmsg;+			unowned string[] sqlite_resultp;++			var ec = this._get_table (sql, out sqlite_resultp, out nrow, out ncolumn, out sqlite_errmsg);++			resultp = new string[(nrow + 1) * ncolumn];+			for (var entry = 0 ; entry < resultp.length ; entry++ ) {+				resultp[entry] = sqlite_resultp[entry];+			}+			Sqlite.Database.free_table (sqlite_resultp);++			if (&errmsg != null) {+				errmsg = sqlite_errmsg;+			}+			Sqlite.Memory.free ((void*) sqlite_errmsg);+			return ec;+		}+		public static int open (string filename, out Database db);+		public static int open_v2 (string filename, out Database db, int flags = OPEN_READWRITE | OPEN_CREATE, string? zVfs = null);+		public int errcode ();+		public unowned string errmsg ();+		public unowned Sqlite.Statement next_stmt (Sqlite.Statement? current);+		public int prepare (string sql, int n_bytes, out Statement stmt, out unowned string tail = null);+		public int prepare_v2 (string sql, int n_bytes, out Statement stmt, out unowned string tail = null);+		public int set_authorizer (AuthorizeCallback? auth);+		[CCode (cname = "sqlite3_db_status")]+		public int status (Sqlite.DatabaseStatus op, out int pCurrent, out int pHighwater, int resetFlag = 0);+		public int table_column_metadata (string db_name, string table_name, string column_name, out string? data_type, out string? collation_sequence, out int? not_null, out int? primary_key, out int? auto_increment);+		public void trace (TraceCallback? xtrace);+		public void profile (ProfileCallback? xprofile);+		public void progress_handler (int n_opcodes, Sqlite.ProgressCallback? progress_handler);+		public void commit_hook (CommitCallback? commit_hook);+		public void rollback_hook (RollbackCallback? rollback_hook);+		public void update_hook (UpdateCallback? update_hook);+		public int create_function (string zFunctionName, int nArg, int eTextRep, void * user_data, UserFuncCallback? xFunc, UserFuncCallback? xStep, UserFuncFinishCallback? xFinal);+		public int create_function_v2 (string zFunctionName, int nArg, int eTextRep, void * user_data, UserFuncCallback? xFunc, UserFuncCallback? xStep, UserFuncFinishCallback? xFinal, GLib.DestroyNotify? destroy = null);+		public int create_collation (string zName, int eTextRep, [CCode (delegate_target_pos = 2.9, type = "int (*)(void *, int,  const void *, int,  const void *)")] CompareCallback xCompare);++		public int wal_autocheckpoint (int N);+		public int wal_checkpoint (string zDb);+		public void* wal_hook (WALHookCallback cb, string db_name, int page_count);+	}++	[CCode (instance_pos = 0)]+	public delegate int AuthorizeCallback (Sqlite.Action action, string? p1, string? p2, string db_name, string? responsible);+	[CCode (instance_pos = 0)]+	public delegate void TraceCallback (string message);+	[CCode (instance_pos = 0)]+	public delegate void ProfileCallback (string sql, uint64 time);+	public delegate int ProgressCallback ();+	public delegate int CommitCallback ();+	public delegate void RollbackCallback ();+	[CCode (has_target = false)]+	public delegate void UserFuncCallback (Sqlite.Context context, [CCode (array_length_pos = 1.1)] Sqlite.Value[] values);+	[CCode (has_target = false)]+	public delegate void UserFuncFinishCallback (Sqlite.Context context);+	[CCode (instance_pos = 0)]+	public delegate void UpdateCallback (Sqlite.Action action, string dbname, string table, int64 rowid);+	[CCode (instance_pos = 0)]+	public delegate int CompareCallback (int alen, void* a, int blen, void* b);+	[CCode (instance_pos = 0)]+	public delegate int WALHookCallback (Sqlite.Database db, string dbname, int pages);++	public unowned string? compileoption_get (int n);+	public int compileoption_used (string option_name);+	public static int complete (string sql);+	[CCode (sentinel = "")]+	public static int config (Sqlite.Config op, ...);+	public unowned string libversion ();+	public int libversion_number ();+	[PrintfFormat]+	public void log (int error_code, string format, ...);+	public unowned string sourceid ();+	public static int status (Sqlite.Status op, out int pCurrent, out int pHighwater, int resetFlag = 0);+	public static int threadsafe ();++	[CCode (cname = "SQLITE_VERSION")]+	public const string VERSION;+	[CCode (cname = "SQLITE_VERSION_NUMBER")]+	public const int VERSION_NUMBER;+	[CCode (cname = "SQLITE_SOURCE_ID")]+	public const string SOURCE_ID;++	/* Dynamically Typed Value Object */+	[Compact]+	[CCode (cname = "sqlite3_value")]+	public class Value {+		[CCode (cname = "sqlite3_value_blob")]+		public void* to_blob ();+		[CCode (cname = "sqlite3_value_bytes")]+		public int to_bytes ();+		[CCode (cname = "sqlite3_value_double")]+		public double to_double ();+		[CCode (cname = "sqlite3_value_int")]+		public int to_int ();+		[CCode (cname = "sqlite3_value_int64")]+		public int64 to_int64 ();+		[CCode (cname = "sqlite3_value_text")]+		public unowned string to_text ();+		[CCode (cname = "sqlite3_value_type")]+		public int to_type ();+		[CCode (cname = "sqlite3_value_numeric_type")]+		public int to_numeric_type ();+	}++	[CCode (cname = "sqlite3_callback", instance_pos = 0)]+	public delegate int Callback (int n_columns, [CCode (array_length = false)] string[] values, [CCode (array_length = false)] string[] column_names);++	[CCode (cname = "SQLITE_OK")]+	public const int OK;+	[CCode (cname = "SQLITE_ERROR")]+	public const int ERROR;+	[CCode (cname = "SQLITE_INTERNAL")]+	public const int INTERNAL;+	[CCode (cname = "SQLITE_PERM")]+	public const int PERM;+	[CCode (cname = "SQLITE_ABORT")]+	public const int ABORT;+	[CCode (cname = "SQLITE_BUSY")]+	public const int BUSY;+	[CCode (cname = "SQLITE_LOCKED")]+	public const int LOCKED;+	[CCode (cname = "SQLITE_NOMEM")]+	public const int NOMEM;+	[CCode (cname = "SQLITE_READONLY")]+	public const int READONLY;+	[CCode (cname = "SQLITE_INTERRUPT")]+	public const int INTERRUPT;+	[CCode (cname = "SQLITE_IOERR")]+	public const int IOERR;+	[CCode (cname = "SQLITE_CORRUPT")]+	public const int CORRUPT;+	[CCode (cname = "SQLITE_NOTFOUND")]+	public const int NOTFOUND;+	[CCode (cname = "SQLITE_FULL")]+	public const int FULL;+	[CCode (cname = "SQLITE_CANTOPEN")]+	public const int CANTOPEN;+	[CCode (cname = "SQLITE_PROTOCOL")]+	public const int PROTOCOL;+	[CCode (cname = "SQLITE_EMPTY")]+	public const int EMPTY;+	[CCode (cname = "SQLITE_SCHEMA")]+	public const int SCHEMA;+	[CCode (cname = "SQLITE_TOOBIG")]+	public const int TOOBIG;+	[CCode (cname = "SQLITE_CONSTRAINT")]+	public const int CONSTRAINT;+	[CCode (cname = "SQLITE_MISMATCH")]+	public const int MISMATCH;+	[CCode (cname = "SQLITE_MISUSE")]+	public const int MISUSE;+	[CCode (cname = "SQLITE_NOLFS")]+	public const int NOLFS;+	[CCode (cname = "SQLITE_AUTH")]+	public const int AUTH;+	[CCode (cname = "SQLITE_FORMAT")]+	public const int FORMAT;+	[CCode (cname = "SQLITE_RANGE")]+	public const int RANGE;+	[CCode (cname = "SQLITE_NOTADB")]+	public const int NOTADB;+	[CCode (cname = "SQLITE_ROW")]+	public const int ROW;+	[CCode (cname = "SQLITE_DONE")]+	public const int DONE;+	[CCode (cname = "SQLITE_OPEN_READONLY")]+	public const int OPEN_READONLY;+	[CCode (cname = "SQLITE_OPEN_READWRITE")]+	public const int OPEN_READWRITE;+	[CCode (cname = "SQLITE_OPEN_CREATE")]+	public const int OPEN_CREATE;+	[CCode (cname = "SQLITE_INTEGER")]+	public const int INTEGER;+	[CCode (cname = "SQLITE_FLOAT")]+	public const int FLOAT;+	[CCode (cname = "SQLITE_BLOB")]+	public const int BLOB;+	[CCode (cname = "SQLITE_NULL")]+	public const int NULL;+	[CCode (cname = "SQLITE3_TEXT")]+	public const int TEXT;+	[CCode (cname = "SQLITE_MUTEX_FAST")]+	public const int MUTEX_FAST;+	[CCode (cname = "SQLITE_MUTEX_RECURSIVE")]+	public const int MUTEX_RECURSIVE;+	[CCode (cname = "SQLITE_UTF8")]+	public const int UTF8;+	[CCode (cname = "SQLITE_UTF16LE")]+	public const int UTF16LE;+	[CCode (cname = "SQLITE_UTF16BE")]+	public const int UTF16BE;+	[CCode (cname = "SQLITE_UTF16")]+	public const int UTF16;+	[CCode (cname = "SQLITE_ANY")]+	public const int ANY;+	[CCode (cname = "SQLITE_UTF16_ALIGNED")]+	public const int UTF16_ALIGNED;++	[CCode (cname = "int", cprefix = "SQLITE_", has_type_id = false)]+	public enum Action {+		CREATE_INDEX,+		CREATE_TABLE,+		CREATE_TEMP_INDEX,+		CREATE_TEMP_TABLE,+		CREATE_TEMP_TRIGGER,+		CREATE_TEMP_VIEW,+		CREATE_TRIGGER,+		CREATE_VIEW,+		DELETE,+		DROP_INDEX,+		DROP_TABLE,+		DROP_TEMP_INDEX,+		DROP_TEMP_TABLE,+		DROP_TEMP_TRIGGER,+		DROP_TEMP_VIEW,+		DROP_TRIGGER,+		DROP_VIEW,+		INSERT,+		PRAGMA,+		READ,+		SELECT,+		TRANSACTION,+		UPDATE,+		ATTACH,+		DETACH,+		ALTER_TABLE,+		REINDEX,+		ANALYZE,+		CREATE_VTABLE,+		DROP_VTABLE,+		FUNCTION,+		SAVEPOINT,+		COPY+	}++	[CCode (cname = "int", cprefix = "SQLITE_CONFIG_", has_type_id = false)]+	public enum Config {+		SINGLETHREAD,+		MULTITHREAD,+		SERIALIZED,+		MALLOC,+		GETMALLOC,+		SCRATCH,+		PAGECACHE,+		HEAP,+		MEMSTATUS,+		MUTEX,+		GETMUTEX,+		LOOKASIDE,+		PCACHE,+		GETPCACHE,+		LOG,+	}++	[CCode (cname = "int", cprefix = "SQLITE_DBSTATUS_", has_type_id = false)]+	public enum DatabaseStatus {+		LOOKASIDE_USED+	}++	[CCode (cname = "int", cprefix = "SQLITE_LIMIT_", has_type_id = false)]+	public enum Limit {+		LENGTH,+		SQL_LENGTH,+		COLUMN,+		EXPR_DEPTH,+		COMPOUND_SELECT,+		VDBE_OP,+		FUNCTION_ARG,+		ATTACHED,+		LIKE_PATTERN_LENGTH,+		VARIABLE_NUMBER,+		TRIGGER_DEPTH+	}++	[CCode (cname = "int", cprefix = "SQLITE_STMTSTATUS_", has_type_id = false)]+	public enum StatementStatus {+		FULLSCAN_STEP,+		SORT+	}++	[CCode (cname = "int", cprefix = "SQLITE_STATUS_", has_type_id = false)]+	public enum Status {+		MEMORY_USED,+		PAGECACHE_USED,+		PAGECACHE_OVERFLOW,+		SCRATCH_USED,+		SCRATCH_OVERFLOW,+		MALLOC_SIZE,+		PARSER_STACK,+		PAGECACHE_SIZE,+		SCRATCH_SIZE+	}++	/* SQL Statement Object */+	[Compact]+	[CCode (free_function = "sqlite3_finalize", cname = "sqlite3_stmt", cprefix = "sqlite3_")]+	public class Statement {+		public int bind_parameter_count ();+		public int bind_parameter_index (string name);+		public unowned string bind_parameter_name (int index);+		public int clear_bindings ();+		public int column_count ();+		public int data_count ();+		public unowned Database db_handle ();+		public int reset ();+		[CCode (cname = "sqlite3_stmt_status")]+		public int status (Sqlite.StatementStatus op, int resetFlg = 0);+		public int step ();+		public int bind_blob (int index, void* value, int n, GLib.DestroyNotify? destroy_notify = null);+		public int bind_double (int index, double value);+		public int bind_int (int index, int value);+		public int bind_int64 (int index, int64 value);+		public int bind_null (int index);+		[CCode (cname = "sqlite3_bind_text")]+		public int _bind_text (int index, string value, int n = -1, GLib.DestroyNotify? destroy_notify = null);+		public int bind_text (int index, owned string value, int n = -1, GLib.DestroyNotify destroy_notify = GLib.g_free);+		public int bind_value (int index, Value value);+		public int bind_zeroblob (int index, int n);+		public void* column_blob (int col);+		public int column_bytes (int col);+		public double column_double (int col);+		public int column_int (int col);+		public int64 column_int64 (int col);+		public unowned string column_text (int col);+		public int column_type (int col);+		public unowned Value column_value (int col);+		public unowned string column_name (int index);+		public unowned string column_database_name (int col);+		public unowned string column_table_name (int col);+		public unowned string column_origin_name (int col);+		public unowned string sql ();+	}++	namespace Memory {+		[CCode (cname = "sqlite3_malloc")]+		public static void* malloc (int n_bytes);+		[CCode (cname = "sqlite3_realloc")]+		public static void* realloc (void* mem, int n_bytes);+		[CCode (cname = "sqlite3_free")]+		public static void free (void* mem);+		[CCode (cname = "sqlite3_release_memory")]+		public static int release (int bytes);+		[CCode (cname = "sqlite3_memory_used")]+		public static int64 used ();+		[CCode (cname = "sqlite3_memory_highwater")]+		public static int64 highwater (int reset = 0);+		[Deprecated (since = "3.7.2", replacement = "Sqlite.Memory.soft_heap_limit64")]+		[CCode (cname = "sqlite3_soft_heap_limit")]+		public static void soft_heap_limit (int limit);+		[CCode (cname = "sqlite3_soft_heap_limit64")]+		public static int64 soft_heap_limit64 (int64 limit = -1);+	}++	[Compact]+	[CCode (cname = "sqlite3_mutex")]+	public class Mutex {+		[CCode (cname = "sqlite3_mutex_alloc")]+		public Mutex (int mutex_type = MUTEX_RECURSIVE);+		public void enter ();+		public int held ();+		public int notheld ();+		public int @try ();+		public void leave ();+	}++	[Compact, CCode (cname = "sqlite3_context", cprefix = "sqlite3_")]+	public class Context {+		public void result_blob (owned uint8[] data, GLib.DestroyNotify? destroy_notify = GLib.g_free);+		public void result_double (double value);+		public void result_error (string value, int error_code);+		public void result_error_toobig ();+		public void result_error_nomem ();+		public void result_error_code (int error_code);+		public void result_int (int value);+		public void result_int64 (int64 value);+		public void result_null ();+		public void result_text (owned string value, int length = -1, GLib.DestroyNotify? destroy_notify = GLib.g_free);+		public void result_value (Sqlite.Value value);+		public void result_zeroblob (int n);++		[CCode (simple_generics = true)]+		public unowned T user_data<T> ();+		[CCode (simple_generics = true)]+		public void set_auxdata<T> (int N, owned T data);+		[CCode (simple_generics = true)]+		public unowned T get_auxdata<T> (int N);+		[CCode (cname = "sqlite3_context_db_handle")]+		public unowned Database db_handle ();+		[CCode (cname = "sqlite3_aggregate_context")]+		public void * aggregate (int n_bytes);+	}++	[Compact, CCode (cname = "sqlite3_backup", free_function = "sqlite3_backup_finish", cprefix = "sqlite3_backup_")]+	public class Backup {+		[CCode (cname = "sqlite3_backup_init")]+		public Backup (Database dest, string dest_name, Database source, string source_name);+		public int step (int nPage);+		public int remaining ();+		public int pagecount ();+	}+}+

Contact

Email: johan.mattsson.m@gmail.com
Mastodon: typo.social/@birdfont
GitHub: johanmattssonm
LinkedIn: johan-mattsson-2ab324112