+
+CLASS(DataSource, Object)
+ STATIC_ATTRIB(DataSource, true, entity, NEW(Object));
+ STATIC_ATTRIB(DataSource, false, entity, NULL);
+ /**
+ * get entry `i` passing `name` and `icon` through `returns` if it is not null
+ * returns `DataSource_false` if out of bounds
+ * otherwise returns an entity or `DataSource_true`
+ */
+ METHOD(DataSource, getEntry, entity(entity this, int i, void(string name, string icon) returns)) { return DataSource_false; }
+ /** return the index of the first match for `find`. optional */
+ METHOD(DataSource, indexOf, int(entity this, string find)) { return -1; }
+ /** reload all entries matching `filter` returning how many matches were found */
+ METHOD(DataSource, reload, int(entity this, string filter)) { return 0; }
+ /** cleanup on shutdown. optional */
+ METHOD(DataSource, destroy, void(entity this)) { }
+ENDCLASS(DataSource)
+
+
+CLASS(StringSource, DataSource)
+ ATTRIB(StringSource, StringSource_str, string, string_null)
+ ATTRIB(StringSource, StringSource_sep, string, string_null)
+ CONSTRUCTOR(StringSource, string str, string sep);
+ METHOD(StringSource, getEntry, entity(entity this, int i, void(string name, string icon) returns));
+ METHOD(StringSource, reload, int(entity this, string filter));
+ENDCLASS(StringSource)
+
+CLASS(CvarStringSource, StringSource)
+ ATTRIB(CvarStringSource, CvarStringSource_cvar, string, string_null)
+ CONSTRUCTOR(CvarStringSource, string cv, string sep);
+ METHOD(CvarStringSource, getEntry, entity(entity this, int i, void(string name, string icon) returns));
+ METHOD(CvarStringSource, reload, int(entity this, string filter));
+ENDCLASS(CvarStringSource)