The 'start' mark passed to doc:content must not now be changed.
Some handlers did change it, others didn't.
Several callers didn't want it changed (so passed dup), a few didn't
care.
Due to the extra chars that can be passed, it might be awkward to return
a precise mark, and the caller might not care.
So leave it up to the callback to report any marks needed, and always
dup the mark before moving it.
Signed-off-by: NeilBrown <neil@brown.name>
### Trivial
- [ ] If an email part doesn't end with newline, last character is swallowed.
-- [ ] What is rule for doc:content? Does the mark move and get passed
+- [X] What is rule for doc:content? Does the mark move and get passed
down, or is it copied and left unchanged?
### Small
*
* If called as doc:content-bytes: return bytes, not chars
*
- * .mark is 'location': to start. This is moved forwards
+ * .mark is 'location': to start. This is not moved.
+ * .mark2, if set, is location to stop.
* .comm2 is 'consume': pass char mark and report if finished.
*
+ * comm2 is passed:
+ * .mark - the mark that was passed in and gets moved
+ * .num - char character just before .mark
+ * .str - num utf8 text after mark. It may not be present
+ * and if it is, at most .num2 bytes can be used
+ * .num2 - usable length of .str
+ *
+ * comm2 it typically embedded in another struct that can
+ * be accessed in the callback (using container_of in C code).
+ * If the caller need to know where the callback aborted, the
+ * callback need to record that somehow.
+ *
+ * comm2 should return 1 if the main char was consumed,
+ * 1+n if n bytes (not chars) from str were consumed
+ * -ve to abort.
+ *
+ * If the callback processes some of 'str', the mark will no longer
+ * be accurate. If it needs an accurate mark, it can walk a copy
+ * forward, or return a suitable count and be called again with an
+ * accurate mark.
*/
struct mark *m = ci->mark;
struct commcache dchar = CCINIT;
if (!m || !ci->comm2)
return Enoarg;
+ m = mark_dup(m);
if (strcmp(ci->key, "doc:content-bytes") == 0)
cmd = "doc:byte";
comm_call(ci->comm2, "consume", ci->home, (nxt & 0x1FFFF), m) > 0)
nxt = ccall(&dchar, cmd, ci->home, 1, m);
+ mark_free(m);
return nxt < 0 ? nxt : 1;
}
*/
int bytes = strcmp(ci->key, "doc:get-bytes") == 0;
struct getstr g;
- struct mark *from = NULL, *to = NULL, *m;
+ struct mark *from = NULL, *to = NULL;
if (ci->mark && ci->mark2) {
if (ci->mark2->seq < ci->mark->seq) {
g.bytes = bytes;
buf_init(&g.b);
g.end = to;
- if (from)
- m = mark_dup(from);
- else
- m = vmark_new(ci->focus, MARK_UNGROUPED, NULL);
- if (!m)
+ if (!from) {
+ from = vmark_new(ci->focus, MARK_UNGROUPED, NULL);
+ if (from)
+ call("doc:set-ref", ci->focus, 1, from);
+ }
+ if (!from)
return Efail;
if (!to) {
to = vmark_new(ci->focus, MARK_UNGROUPED, NULL);
call("doc:set-ref", ci->focus, 0, to);
}
call_comm(bytes ? "doc:content-bytes" : "doc:content",
- ci->focus, &g.c, 0, m, NULL, 0, to);
- mark_free(m);
+ ci->focus, &g.c, 0, from, NULL, 0, to);
+ if (from != ci->mark && from != ci->mark2)
+ mark_free(from);
if (to != ci->mark && to != ci->mark2)
mark_free(to);
comm_call(ci->comm2, "callback:get-str", ci->focus, g.b.len, NULL,
if (!ci->mark || !ci->comm2)
return Enoarg;
- m = ci->mark;
+ m = mark_dup(ci->mark);
m2 = ci->mark2;
cb.last_ret = 1;
while (cb.last_ret > 0 && m->ref.docnum < mpi->nparts &&
post_move(m);
}
}
+ mark_free(m);
return ret;
}
NULL, Pattern);
if (ptn) {
char *new2;
- struct mark *tmp = mark_dup(m);
- call_comm("doc:content", esi->target, ptn, 0, tmp);
- mark_free(tmp);
+ call_comm("doc:content", esi->target, ptn, 0, m);
new2 = comm_call_ret(strsave, ptn, "interp",
esi->target, 0, NULL, new);
if (new2)
DEF_CMD(crop_content)
{
struct crop_data *cd = ci->home->data;
- struct mark *m2;
+ struct mark *m, *m2;
int ret;
- crop(ci->mark, cd);
+ if (!ci->mark)
+ return Enoarg;
+ m = mark_dup(ci->mark);
+ crop(m, cd);
crop(ci->mark2, cd);
if (ci->mark2)
m2 = ci->mark2;
else
m2 = mark_dup(cd->end);
ret = home_call_comm(ci->home->parent, ci->key, ci->home,
- ci->comm2, 0, ci->mark, NULL, 0, m2);
+ ci->comm2, 0, m, NULL, 0, m2);
+ mark_free(m);
if (m2 != ci->mark2)
mark_free(m2);
return ret;
{
/* if 'end' is NULL, go all the way to EOF */
struct clcb cl;
- struct mark *tmp;
cl.lines = 0;
cl.words = 0;
*linep = 0;
*wordp = 0;
*charp = 0;
- tmp = mark_dup(start);
- if (call_comm("doc:content", p, &cl.c, 0, tmp, NULL, 0, end) <= 0 ||
- (add_marks && cl.add_marks == 0)) {
- mark_free(tmp);
+ if (call_comm("doc:content", p, &cl.c, 0, start, NULL, 0, end) <= 0 ||
+ (add_marks && cl.add_marks == 0))
return;
- }
- mark_free(tmp);
if (cl.add_marks && cl.start && cl.start != start && cl.chars == 0) {
mark_free(cl.start);
DEF_CMD(text_equals)
{
struct texteql te;
- struct mark *m;
if (!ci->str || !ci->mark)
return Enoarg;
- m = mark_dup(ci->mark);
te.c = equal_test;
te.text = ci->str;
te.matched = False;
- call_comm("doc:content", ci->focus, &te.c, 0, m);
- mark_free(m);
+ call_comm("doc:content", ci->focus, &te.c, 0, ci->mark);
return te.matched ? 1 : Efalse;
}
return 1
cmd = focus.call("make-search", ptn,
edlib.RXLF_ANCHORED|edlib.RXLF_BACKTRACK, ret='comm')
- m2 = m.dup()
- focus.call("doc:content", m2, cmd)
+ focus.call("doc:content", m, cmd)
f = cmd("getcapture", "len", focus, 1)-1
if self.which == 0 or self.which > f:
# get the "after" section
wcmd = focus.call("MakeWiggle", ret='comm')
if not wcmd:
return edlib.Efail
+ m2 = m.dup()
focus.call("doc:EOL", 1, m2, 1)
m3 = mark.dup()
focus.call("doc:EOL", -1, m3)
if c and c == '>':
self.getvar("reinit", focus,
edlib.RXLF_ANCHORED | edlib.RXLF_BACKTRACK)
- focus.call("doc:content", m.dup(), self.getvar)
+ focus.call("doc:content", m, self.getvar)
nm = self.getvar("interp", focus, "\\1", ret='str')
# replace this line
focus.call("doc:EOL", 1, m)
DEF_CMD(format_content)
{
+ struct mark *m;
+
if (!ci->mark || !ci->comm2)
return Enoarg;
if (ci->num)
/* Cannot handle bytes */
return Einval;
- while (doc_following(ci->focus, ci->mark) != WEOF) {
+ m = mark_dup(ci->mark);
+ while (doc_following(ci->focus, m) != WEOF) {
const char *l, *c;
wint_t w;
- l = do_format(ci->focus, ci->mark, NULL, -1, 0);
+ l = do_format(ci->focus, m, NULL, -1, 0);
if (!l)
break;
- doc_next(ci->focus, ci->mark);
+ doc_next(ci->focus, m);
c = l;
while (*c) {
w = get_utf8(&c, NULL);
if (w >= WERR ||
- comm_call(ci->comm2, "consume", ci->focus, w, ci->mark) <= 0)
+ comm_call(ci->comm2, "consume", ci->focus, w, m) <= 0)
/* Finished */
break;
}
if (*c)
break;
}
+ mark_free(m);
return 1;
}
/* Cannot handle bytes */
return Einval;
set_format(focus, rd);
+ m = mark_dup(m);
pane_set_time(home);
do {
(!end || mark_ordered_or_same(m, end)) &&
comm_call(ci->comm2, "consume", ci->focus, nxt, m) > 0);
+ mark_free(m);
return 1;
}