diff options
| author | Quentin Carbonneaux | 2014-09-03 23:00:02 -0400 |
|---|---|---|
| committer | Quentin Carbonneaux | 2014-09-03 23:00:02 -0400 |
| commit | 9497069d9c767965118d1bb9bd6c5b3dc3f8ee38 (patch) | |
| tree | 0153b3354990e0d6ab06d9d78bc61d268ee70813 | |
| parent | bc5d8f20c0e5cbbafb7d1ae81af0c47c2217a103 (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.c | 18 | ||||
| -rw-r--r-- | win.c | 36 | ||||
| -rw-r--r-- | win.h | 2 |
3 files changed, 40 insertions, 16 deletions
@@ -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; } @@ -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--) { @@ -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); |
