summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorQuentin Carbonneaux2014-09-03 23:00:02 -0400
committerQuentin Carbonneaux2014-09-03 23:00:02 -0400
commit9497069d9c767965118d1bb9bd6c5b3dc3f8ee38 (patch)
tree0153b3354990e0d6ab06d9d78bc61d268ee70813
parentbc5d8f20c0e5cbbafb7d1ae81af0c47c2217a103 (diff)
add window deletion code
The bug in exec.c can now be triggered, if a command outputs after its window was deleted an invalid buffer pointer is used.
-rw-r--r--exec.c18
-rw-r--r--win.c36
-rw-r--r--win.h2
3 files changed, 40 insertions, 16 deletions
diff --git a/exec.c b/exec.c
index 978cf65..70f2d0e 100644
--- a/exec.c
+++ b/exec.c
@@ -36,6 +36,7 @@ static int put(W *, EBuf *, unsigned);
static int look(W *, EBuf *, unsigned);
static int run(W *, EBuf *, unsigned);
static int new(W *, EBuf *, unsigned);
+static int del(W *, EBuf *, unsigned);
static char *errstr;
static ECmd etab[] = {
@@ -43,6 +44,7 @@ static ECmd etab[] = {
{ "Put", put },
{ "Look", look },
{ "New", new },
+ { "Del", del },
{ 0, run },
};
@@ -320,12 +322,24 @@ look(W *w, EBuf *eb, unsigned p0)
}
static int
-new(W *w, EBuf *eb, unsigned pos)
+new(W *w, EBuf *eb, unsigned p0)
{
- (void)eb; (void)pos;
w = win_new(eb_new());
if (w)
curwin = win_tag_toggle(w);
+ else
+ err(eb, p0, "no more windows");
+ return 0;
+}
+
+static int
+del(W *w, EBuf *eb, unsigned p0)
+{
+ w = win_delete(w);
+ if (w)
+ curwin = w;
+ else
+ err(eb, p0, "last window");
return 0;
}
diff --git a/win.c b/win.c
index f5af3ac..5122864 100644
--- a/win.c
+++ b/win.c
@@ -70,14 +70,12 @@ win_new(EBuf *eb)
int i, x, size;
assert(eb);
-
for (w1=wins;; w1++) {
if (w1 - wins >= MaxWins)
return 0;
if (!w1->eb)
break;
}
-
for (i=0; (w = screen[i]) && screen[i+1]; i++)
;
if (!w) {
@@ -89,27 +87,40 @@ win_new(EBuf *eb)
x = w->rectx + w->rectw + g->border;
i++;
}
-
w1->eb = eb;
move(w1, x, 0, size, fheight);
screen[i] = w1;
screen[i+1] = 0;
-
return w1;
}
/* win_delete - Delete a window created by win_new.
+ * An adjacent window is returned.
*/
-void
+W *
win_delete(W *w)
{
- assert(w >= wins);
- assert(w < wins+MaxWins);
-
+ W *w1, *sw;
+ int rx;
+
+ if (!screen[1])
+ return 0;
+ for (sw = screen; *sw != w; sw++)
+ assert(*sw);
+ if (sw == screen) {
+ w1 = sw[1];
+ rx = 0;
+ } else {
+ w1 = sw[-1];
+ rx = w1->rectx;
+ }
+ move(w1, rx, 0, w->rectw+g->border+w1->rectw, fheight);
memset(w, 0, sizeof(W));
w->eb = 0;
- // FIXME, create an invariant such that win_new can be simplified
- // also, do not delete if only one window is left
+ memmove(sw, sw+1, (MaxWins-(sw-screen))*sizeof(W*));
+ if (tag.visible && tag.owner == w)
+ tag.visible = 0;
+ return w1;
}
/* win_at - Return the buffer offset at the specified location,
@@ -177,9 +188,8 @@ win_move(W *w, int x, int y)
}
for (i=j=0; screen[i+1]; i++)
if (screen[i] == w) {
- w1 = screen[i+1];
- screen[i+1] = screen[i];
- screen[i] = w1;
+ screen[i] = screen[i+1];
+ screen[i+1] = w;
j++;
}
for (; i>0 && x < screen[i-1]->rectx; i--) {
diff --git a/win.h b/win.h
index 47800b2..111d44b 100644
--- a/win.h
+++ b/win.h
@@ -33,7 +33,7 @@ enum CursorLoc { CTop, CMid, CBot };
void win_init(struct gui *g);
W *win_new(EBuf *eb);
-void win_delete(W *);
+W *win_delete(W *);
unsigned win_at(W *w, int x, int y);
W *win_which(int x, int y);
void win_move(W *, int x, int y);