[1012] in BarnOwl Developers
[D-O-H] r997 - branches/barnowl_sqlite/owl
daemon@ATHENA.MIT.EDU (nelhage@MIT.EDU)
Thu Oct 29 18:12:07 2009
Resent-From: nelhage@mit.edu
Resent-To: barnowl-dev-mtg@charon.mit.edu
X-Original-To: nelhage@nelhage.com
To: dirty-owl-hackers@MIT.EDU
From: nelhage@MIT.EDU
Reply-to: dirty-owl-hackers@MIT.EDU
Date: Sat, 29 Mar 2008 20:48:00 -0400 (EDT)
Author: nelhage
Date: 2008-03-29 20:48:00 -0400 (Sat, 29 Mar 2008)
New Revision: 997
Modified:
branches/barnowl_sqlite/owl/global.c
branches/barnowl_sqlite/owl/owl.c
branches/barnowl_sqlite/owl/owl.h
branches/barnowl_sqlite/owl/perlwrap.pm
branches/barnowl_sqlite/owl/view.c
Log:
Move views and view iterators into perl code
Modified: branches/barnowl_sqlite/owl/global.c
===================================================================
--- branches/barnowl_sqlite/owl/global.c 2008-03-29 21:16:07 UTC (rev 996)
+++ branches/barnowl_sqlite/owl/global.c 2008-03-30 00:48:00 UTC (rev 997)
@@ -55,8 +55,6 @@
owl_list_create(&(g->messagequeue));
owl_dict_create(&(g->styledict));
g->curmsg_vert_offset=0;
- g->curmsg = owl_view_iterator_new();
- g->topmsg = owl_view_iterator_new();
g->resizepending=0;
g->typwinactive=0;
g->direction=OWL_DIRECTION_DOWNWARDS;
@@ -93,7 +91,6 @@
owl_global_set_confdir(g, cd);
owl_free(cd);
- owl_mainwin_init(&(g->mw));
owl_popwin_init(&(g->pw));
g->aim_screenname=NULL;
@@ -121,6 +118,15 @@
g->fmtext_seq = 0;
}
+/* Called once perl has been initialized */
+void owl_global_complete_setup(owl_global *g)
+{
+ owl_mainwin_init(&(g->mw));
+ g->msglist = owl_messagelist_new();
+ g->curmsg = owl_view_iterator_new();
+ g->topmsg = owl_view_iterator_new();
+}
+
void _owl_global_setup_windows(owl_global *g) {
int cols, typwin_lines;
Modified: branches/barnowl_sqlite/owl/owl.c
===================================================================
--- branches/barnowl_sqlite/owl/owl.c 2008-03-29 21:16:07 UTC (rev 996)
+++ branches/barnowl_sqlite/owl/owl.c 2008-03-30 00:48:00 UTC (rev 997)
@@ -264,8 +264,7 @@
exit(1);
}
- /* Now that we have perl, we can initialize the msssage list*/
- g.msglist = owl_messagelist_new();
+ owl_global_complete_setup(&g);
/* setup the built-in styles */
owl_function_debugmsg("startup: creating built-in styles");
Modified: branches/barnowl_sqlite/owl/owl.h
===================================================================
--- branches/barnowl_sqlite/owl/owl.h 2008-03-29 21:16:07 UTC (rev 996)
+++ branches/barnowl_sqlite/owl/owl.h 2008-03-30 00:48:00 UTC (rev 997)
@@ -418,7 +418,7 @@
int cachedmsgid; /* cached msgid: should move into view eventually */
} owl_filter;
-typedef struct _owl_view {
+/* typedef struct _owl_view {
char *name;
char *filtname;
owl_list messages;
@@ -427,8 +427,11 @@
typedef struct _owl_view_iterator {
owl_view *view;
int index;
-} owl_view_iterator;
+ } owl_view_iterator; */
+typedef SV owl_view;
+typedef SV owl_view_iterator;
+
typedef struct _owl_mainwin {
int curtruncated;
int lasttruncated;
Modified: branches/barnowl_sqlite/owl/perlwrap.pm
===================================================================
--- branches/barnowl_sqlite/owl/perlwrap.pm 2008-03-29 21:16:07 UTC (rev 996)
+++ branches/barnowl_sqlite/owl/perlwrap.pm 2008-03-30 00:48:00 UTC (rev 997)
@@ -380,6 +380,175 @@
#####################################################################
#####################################################################
+package BarnOwl::View;
+
+sub get_name {return shift->{name}};
+sub messages {return shift->{messages}};
+sub get_filter {return shift->{filter}};
+
+sub new {
+ my $class = shift;
+ my $name = shift;
+ my $filter = shift;
+ my $self = {messages => [],
+ name => $name,
+ filter => $filter};
+ bless $self, $class;
+ $self->recalculate;
+ return $self;
+}
+
+sub consider_message {
+ my $self = shift;
+ my $msg = shift;
+ if(BarnOwl::filter_message_match($self->get_filter, $msg)) {
+ push @{$self->messages}, $msg;
+ }
+}
+
+sub recalculate {
+ my $self = shift;
+ my $ml = BarnOwl::message_list();
+ $ml->start_iterate;
+ $self->{messages} = [];
+ while(my $msg = $ml->iterate_next) {
+ $self->consider_message($msg);
+ }
+}
+
+sub new_filter {
+ my $self = shift;
+ my $filter = shift;
+ $self->{filter} = $filter;
+ $self->recalculate;
+}
+
+sub is_empty {
+ my $self = shift;
+ return $self->_size == 0;
+}
+
+sub _size {
+ my $self = shift;
+ return scalar @{$self->messages};
+}
+
+#####################################################################
+#####################################################################
+
+package BarnOwl::View::Iterator;
+
+sub view {return shift->{view}}
+sub index {return shift->{index}}
+
+sub new {
+ my $class = shift;
+ my $self = {
+ view => undef,
+ index => undef
+ };
+ return bless $self, $class;
+}
+
+sub invalidate {
+ my $self = shift;
+ $self->{view} = undef;
+ $self->{index} = undef;
+}
+
+sub initialize_at_start {
+ my $self = shift;
+ my $view = shift;
+ $self->{view} = $view;
+ $self->{index} = 0;
+}
+
+sub initialize_at_end {
+ my $self = shift;
+ my $view = shift;
+ $self->{view} = $view;
+ $self->{index} = $self->view->_size - 1;
+}
+
+sub initialize_at_id {
+ my $self = shift;
+ my $view = shift;
+ my $id = shift;
+ $self->{view} = $view;
+ my $list = $self->view->messages;
+ my $left = 0;
+ my $right = scalar @{$list} - 1;
+ my $mid;
+ while($left <= $right) {
+ $mid = ($left + $right)/2;
+ if($list->[$mid]->id < $id) {
+ $left = $mid + 1;
+ } else {
+ $right = $mid - 1;
+ }
+ }
+ $self->{index} = $mid;
+}
+
+sub clone {
+ my $self = shift;
+ my $other = shift;
+ $self->{view} = $other->{view};
+ $self->{index} = $other->{index};
+}
+
+sub has_prev {
+ my $self = shift;
+ return $self->index > 0;
+}
+
+sub has_next {
+ my $self = shift;
+ return $self->index < $self->view->_size - 1;
+}
+
+sub at_start {
+ my $self = shift;
+ return $self->index < 0;
+}
+
+sub at_end {
+ my $self = shift;
+ return $self->index >= $self->view->_size;
+}
+
+
+sub valid {
+ my $self = shift;
+ return defined($self->view) &&
+ !$self->at_start &&
+ !$self->at_end;
+}
+
+sub prev {
+ my $self = shift;
+ $self->{index}-- unless $self->at_start
+}
+
+sub next {
+ my $self = shift;
+ $self->{index}++ unless $self->at_end
+}
+
+sub get_message {
+ my $self = shift;
+ return $self->view->messages->[$self->index];
+}
+
+sub cmp {
+ my $self = shift;
+ my $other = shift;
+ return $self->index - $other->index;
+}
+
+#####################################################################
+#####################################################################
+
package BarnOwl::Message;
use POSIX qw(ctime);
Modified: branches/barnowl_sqlite/owl/view.c
===================================================================
--- branches/barnowl_sqlite/owl/view.c 2008-03-29 21:16:07 UTC (rev 996)
+++ branches/barnowl_sqlite/owl/view.c 2008-03-30 00:48:00 UTC (rev 997)
@@ -1,35 +1,41 @@
#include <stdlib.h>
+#define OWL_PERL
#include "owl.h"
static const char fileIdent[] = "$Id$";
-owl_view* owl_view_new(char *name, char *filtname)
+owl_view_iterator* owl_view_new(char *name, char *filtname)
{
- owl_view *v = owl_malloc(sizeof(owl_view));
- v->name=owl_strdup(name);
- v->filtname=owl_strdup(filtname);
- owl_list_create(&(v->messages));
- owl_view_recalculate(v);
- return v;
+ char *args[] = {name, filtname};
+ return owl_perl_new_argv("BarnOwl::View", args, 2);
}
char *owl_view_get_name(owl_view *v)
{
- return(v->name);
+ SV *name;
+ OWL_PERL_CALL_METHOD(v, "get_name",
+ /* no args */,
+ /* error message */
+ "Error in get_name: %s",
+ 1 /* fatal errors */,
+ name = SvREFCNT_inc(POPs););
+ sv_2mortal(name);
+ return SvPV_nolen(name);
}
owl_filter * owl_view_get_filter(owl_view *v)
{
- return owl_global_get_filter(&g, v->filtname);
+ return owl_global_get_filter(&g, owl_view_get_filtname(v));
}
/* if the message matches the filter then add to view */
void owl_view_consider_message(owl_view *v, owl_message *m)
{
- if (owl_filter_message_match(owl_view_get_filter(v), m)) {
- owl_list_append_element(&(v->messages),
- (void*)owl_message_get_id(m));
- }
+ OWL_PERL_CALL_METHOD(v, "consider_message",
+ XPUSHs((SV*)m);,
+ "Error in consider_message: %s",
+ /* fatal */ 1,
+ OWL_PERL_VOID_CALL);
}
/* remove all messages, add all the global messages that match the
@@ -37,84 +43,33 @@
*/
void owl_view_recalculate(owl_view *v)
{
- owl_messagelist *gml;
- owl_list *ml;
- owl_message *m;
- owl_filter *f;
-
- gml=owl_global_get_msglist(&g);
- ml=&(v->messages);
-
- /* nuke the old list */
- owl_list_free_simple(ml);
- owl_list_create(ml);
-
- /* find all the messages we want */
- owl_messagelist_start_iterate(gml);
- f = owl_view_get_filter(v);
- while((m = owl_messagelist_iterate_next(gml)) != NULL) {
- if (owl_filter_message_match(f, m)) {
- owl_list_append_element(ml, (void*)owl_message_get_id(m));
- }
- }
+ OWL_PERL_CALL_METHOD(v, "recalculate",
+ /* no args */,
+ "Error in recalculate: %s",
+ /* fatal */ 1,
+ OWL_PERL_VOID_CALL);
}
void owl_view_new_filter(owl_view *v, char *filtname)
{
- owl_free(v->filtname);
- v->filtname = owl_strdup(filtname);
- owl_view_recalculate(v);
+ OWL_PERL_CALL_METHOD(v, "new_filter",
+ mXPUSHp(filtname, strlen(filtname));,
+ "Error in new_filter: %s",
+ /* fatal */ 1,
+ OWL_PERL_VOID_CALL);
}
-owl_message *_owl_view_get_element(owl_view *v, int index)
-{
- if(index < 0 || index >= _owl_view_get_size(v))
- return NULL;
- int id = (int)owl_list_get_element(&(v->messages), index);
- return owl_messagelist_get_by_id(owl_global_get_msglist(&g), id);
-}
-
int owl_view_is_empty(owl_view *v)
{
- return owl_list_get_size(&(v->messages)) == 0;
+ int empty;
+ OWL_PERL_CALL_METHOD(v, "is_empty",
+ /* no args */,
+ "Error: is_empty: %s",
+ /* fatal */ 1,
+ empty = POPi);
+ return empty;
}
-int _owl_view_get_size(owl_view *v)
-{
- return(owl_list_get_size(&(v->messages)));
-}
-
-/* Returns the position in the view with a message closest
- * to the passed msgid. */
-int _owl_view_get_nearest_to_msgid(owl_view *v, int targetid)
-{
- int first, last, mid = 0, max, bestdist, curid = 0;
-
- first = 0;
- last = max = _owl_view_get_size(v) - 1;
- while (first <= last) {
- mid = (first + last) / 2;
- curid = (int)owl_list_get_element(&(v->messages), mid);
- if (curid == targetid) {
- return(mid);
- } else if (curid < targetid) {
- first = mid + 1;
- } else {
- last = mid - 1;
- }
- }
- bestdist = abs(targetid-curid);
- if (curid < targetid && mid+1 < max) {
- curid = (int)owl_list_get_element(&(v->messages), mid+1);
- mid = (bestdist < abs(targetid-curid)) ? mid : mid+1;
- }
- else if (curid > targetid && mid-1 >= 0) {
- curid = (int)owl_list_get_element(&(v->messages), mid-1);
- mid = (bestdist < abs(targetid-curid)) ? mid : mid-1;
- }
- return mid;
-}
-
/* saves the current message position in the filter so it can
* be restored later if we switch back to this filter. */
void owl_view_save_curmsgid(owl_view *v, int curid)
@@ -126,121 +81,187 @@
void owl_view_to_fmtext(owl_view *v, owl_fmtext *fm)
{
owl_fmtext_append_normal(fm, "Name: ");
- owl_fmtext_append_normal(fm, v->name);
+ owl_fmtext_append_normal(fm, owl_view_get_name(v));
owl_fmtext_append_normal(fm, "\n");
owl_fmtext_append_normal(fm, "Filter: ");
owl_fmtext_append_normal(fm, owl_view_get_filtname(v));
owl_fmtext_append_normal(fm, "\n");
-
- /* owl_fmtext_append_normal(fm, "Style: ");
- owl_fmtext_append_normal(fm, owl_style_get_name(v->style));
- owl_fmtext_append_normal(fm, "\n"); */
}
char *owl_view_get_filtname(owl_view *v)
{
- return v->filtname;
+ SV *name;
+ OWL_PERL_CALL_METHOD(v, "get_filter",
+ /* no args */,
+ "Error: get_filter: %s",
+ 1 /* fatal errors */,
+ name = SvREFCNT_inc(POPs));
+ sv_2mortal(name);
+ return SvPV_nolen(name);
}
void owl_view_free(owl_view *v)
{
- owl_list_free_simple(&(v->messages));
- if (v->name) owl_free(v->name);
- if (v->filtname) owl_free(v->filtname);
+ SvREFCNT_dec((SV*)v);
}
-/* View Iterators */
+/********************************************************************
+ * View iterators
+ *
+ * The only supported way to access the elements of a view are through
+ * the view iterator API presented here.
+ *
+ * There are three ways to initialize an iterator:
+ * * At the first of the view's messages
+ * * Given an ID, at the message in the view closest to that ID
+ * * At the last of the view's messages
+ *
+ * In addition to pointing at a message, an iterator may point at two
+ * special positions, before the first message in the list, and after
+ * the last message in the list
+ *
+ * The predicates is_at_start and is_at_end test for these special
+ * iterators.
+ *
+ * The predicates has_next and has_prev test whether an iterator
+ * points to the first or last message in the view
+ *
+ * _prev and _next, if applied to the special "start" or "end"
+ * iterators respectively, are no-ops.
+ */
-owl_view_iterator* owl_view_iterator_new()
+#define CALL_BOOL(it, method) \
+ int _rv; \
+ OWL_PERL_CALL_METHOD(it, method, \
+ /* No args */, \
+ "Error: " #method ": %s", \
+ /* fatal */ 1, \
+ _rv = POPi); \
+ return _rv;
+
+#define CALL_VOID(it, method) \
+ OWL_PERL_CALL_METHOD(it, method, \
+ /* No args */, \
+ "Error: " #method ": %s", \
+ /* fatal */ 1, \
+ OWL_PERL_VOID_CALL); \
+
+owl_view_iterator * owl_view_iterator_new()
{
- return owl_malloc(sizeof(owl_view_iterator));
+ return owl_perl_new("BarnOwl::View::Iterator");
}
void owl_view_iterator_invalidate(owl_view_iterator *it)
{
- it->index = -1;
- it->view = NULL;
+ CALL_VOID(it, "invalidate");
}
void owl_view_iterator_init_id(owl_view_iterator *it, owl_view *v, int message_id)
{
- it->view = v;
- it->index = _owl_view_get_nearest_to_msgid(v, message_id);
+ OWL_PERL_CALL_METHOD(it, "initialize_at_id",
+ /* args */
+ XPUSHs(v);
+ mXPUSHi(message_id);,
+ "Error: initialize at id: %s",
+ /* fatal */ 1,
+ OWL_PERL_VOID_CALL);
}
void owl_view_iterator_init_start(owl_view_iterator *it, owl_view *v)
{
- it->view = v;
- it->index = 0;
+ OWL_PERL_CALL_METHOD(it, "initialize_at_start",
+ /* args */
+ XPUSHs(v);,
+ "Error: initialize at start: %s",
+ /* fatal */ 1,
+ OWL_PERL_VOID_CALL);
}
void owl_view_iterator_init_end(owl_view_iterator *it, owl_view *v)
{
- it->view = v;
- it->index = _owl_view_get_size(v) - 1;
+ OWL_PERL_CALL_METHOD(it, "initialize_at_end",
+ /* args */
+ XPUSHs(v);,
+ "Error: initialize at end: %s",
+ /* fatal */ 1,
+ OWL_PERL_VOID_CALL);
}
void owl_view_iterator_clone(owl_view_iterator *dst, owl_view_iterator *src)
{
- dst->view = src->view;
- dst->index = src->index;
+ OWL_PERL_CALL_METHOD(dst, "clone",
+ XPUSHs(src);,
+ "Error: clone: %s",
+ /* fatal */ 1,
+ OWL_PERL_VOID_CALL);
}
int owl_view_iterator_has_prev(owl_view_iterator *it)
{
- return it->index > 0;
+ CALL_BOOL(it, "has_prev");
}
int owl_view_iterator_has_next(owl_view_iterator *it)
{
- return it->index < _owl_view_get_size(it->view) - 1;
+ CALL_BOOL(it, "has_next");
}
int owl_view_iterator_is_at_end(owl_view_iterator *it)
{
- return it->index >= _owl_view_get_size(it->view);
+ CALL_BOOL(it, "at_end");
}
int owl_view_iterator_is_at_start(owl_view_iterator *it)
{
- return it->index < 0;
+ CALL_BOOL(it, "at_start");
}
int owl_view_iterator_is_valid(owl_view_iterator *it)
{
- return it->view != NULL && it->index >= 0 && it->index < _owl_view_get_size(it->view);
+ CALL_BOOL(it, "valid");
}
void owl_view_iterator_prev(owl_view_iterator *it)
{
- if(!owl_view_iterator_is_at_start(it))
- it->index--;
+ CALL_VOID(it, "prev");
}
void owl_view_iterator_next(owl_view_iterator *it)
{
- if(!owl_view_iterator_is_at_end(it))
- it->index++;
+ CALL_VOID(it, "next");
}
-owl_message * owl_view_iterator_get_message(owl_view_iterator *it)
+owl_message* owl_view_iterator_get_message(owl_view_iterator *it)
{
- return _owl_view_get_element(it->view, it->index);
+ SV *msg;
+ OWL_PERL_CALL_METHOD(it, "get_message",
+ /* no args */,
+ "Error: get_message: %s",
+ /* fatal errors */ 1,
+ msg = POPs;
+ if(SvROK(msg)) SvREFCNT_inc(msg);
+ );
+ return SvROK(msg) ? sv_2mortal(msg) : NULL;
}
int owl_view_iterator_cmp(owl_view_iterator *it1, owl_view_iterator *it2)
{
- return it1->index - it2->index;
+ int cmp;
+ OWL_PERL_CALL_METHOD(it1, "cmp",
+ XPUSHs(it2);,
+ "Error: cmp: %s",
+ /* fatal */ 1,
+ cmp = POPi);
+ return cmp;
}
void owl_view_iterator_free(owl_view_iterator *it)
{
- owl_free(it);
+ SvREFCNT_dec(it);
}
owl_view_iterator* owl_view_iterator_free_later(owl_view_iterator *it)
{
- /* do-de-doo, leaking da memory... */
- return it;
+ return sv_2mortal(it);
}